📜 ⬆️ ⬇️

Site on c ++ (CppCMS). Part 1

Hello dear% username%.
Today I would like to share with you my personal experience in creating a Web site on CppCMS (template library on c ++). You can call this "help a novice programmer on CppCMS."

Why write a site on c ++


The pros and cons of such a decision can be very diverse and, in order not to provoke a war of “language schools”, I will draw an analogy with cars: “I bought this one. Like. I drive. I do not want to sell!
Of the additional arguments will be the fact that this language is specialized for my workplace.

Let's write something already


However before

Before writing a site, you first have to put it (CppCMS) on a working machine. The library in the most impudent way demands Boost c ++, pcre, crypt, python, icu for its work and, in spite of cross-platform, is much more pleasantly placed under * nix systems.
The very same construction comes down to the banal:

mkdir build cd build cmake .. make make install 

There should be no problems, everything is built automatically, and I have never been upset.
')
Looking ahead, I would like to say that for comfortable work it is desirable that the development environment be able to perform custom construction steps, as well as have a conveniently editable "parser", I use QtCreator.
I will describe all further steps as applied to the above-mentioned environment, since the construction using the command line is well reviewed on the site of the library itself. I also want to note that some build actions will be automated by bash scripts (although it would be enough to write a “user step” at the build stage)

Before starting work, it is advisable to add syntax highlighting for QtCreator, so that it recognizes special * .tmpl files that are used as templates. This tmpl.xml file (slightly modified HTML highlighting) should be in the “qtcreator / generic-highlighter / tmpl.xml” configs folder:

Full text file
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE language SYSTEM "language.dtd" [ <!ENTITY name "[A-Za-z_:][\w.:_-]*"> <!ENTITY entref "&(#[0-9]+|#[xX][0-9A-Fa-f]+|&name;);"> ]> <language name="TMPL" version="1" kateversion="2.4" section="Markup" extensions="*.tmpl" mimetype="text/tmpl" author="Wilbert Berendsen ( original HTML author)(wilbert@kde.nl)" license="LGPL" priority="10"> <highlighting> <contexts> <context name="Start" attribute="Normal Text" lineEndContext="#stay"> <IncludeRules context="FindHTML" /> </context> <context name="FindHTML" attribute="Normal Text" lineEndContext="#stay"> <DetectSpaces/> <DetectIdentifier/> <StringDetect attribute="Comment" context="Comment" String="<!--" beginRegion="comment" /> <StringDetect attribute="Commenttmpl" context="Commenttmpl" String="<%" beginRegion="commenttmpl" /> <StringDetect attribute="CDATA" context="CDATA" String="<![CDATA[" beginRegion="cdata" /> <RegExpr attribute="Doctype" context="Doctype" String="<!DOCTYPE\s+" beginRegion="doctype" /> <RegExpr attribute="Processing Instruction" context="PI" String="<\?[\w:-]*" beginRegion="pi" /> <RegExpr attribute="Element" context="CSS" String="<style\b" insensitive="TRUE" beginRegion="style" /> <RegExpr attribute="Element" context="JS" String="<script\b" insensitive="TRUE" beginRegion="script" /> <RegExpr attribute="Element" context="El Open" String="<pre\b" insensitive="TRUE" beginRegion="pre" /> <RegExpr attribute="Element" context="El Open" String="<div\b" insensitive="TRUE" beginRegion="div" /> <RegExpr attribute="Element" context="El Open" String="<table\b" insensitive="TRUE" beginRegion="table" /> <RegExpr attribute="Element" context="El Open" String="<ul\b" insensitive="TRUE" beginRegion="ul" /> <RegExpr attribute="Element" context="El Open" String="<ol\b" insensitive="TRUE" beginRegion="ol" /> <RegExpr attribute="Element" context="El Open" String="<dl\b" insensitive="TRUE" beginRegion="dl" /> <RegExpr attribute="Element" context="El Open" String="<&name;" /> <RegExpr attribute="Element" context="El Close" String="</pre\b" insensitive="TRUE" endRegion="pre" /> <RegExpr attribute="Element" context="El Close" String="</div\b" insensitive="TRUE" endRegion="div" /> <RegExpr attribute="Element" context="El Close" String="</table\b" insensitive="TRUE" endRegion="table" /> <RegExpr attribute="Element" context="El Close" String="</ul\b" insensitive="TRUE" endRegion="ul" /> <RegExpr attribute="Element" context="El Close" String="</ol\b" insensitive="TRUE" endRegion="ol" /> <RegExpr attribute="Element" context="El Close" String="</dl\b" insensitive="TRUE" endRegion="dl" /> <RegExpr attribute="Element" context="El Close" String="</&name;" /> <!-- as long as kde gives DTDs the text/html mimetype--><IncludeRules context="FindDTDRules" /> <IncludeRules context="FindEntityRefs" /> </context> <context name="FindEntityRefs" attribute="Other Text" lineEndContext="#stay"> <StringDetect attribute="Commenttmpl" context="Commenttmpl" String="<%" beginRegion="commenttmpl" /> <RegExpr attribute="EntityRef" context="#stay" String="&entref;" /> <AnyChar attribute="Error" context="#stay" String="&<" /> </context> <context name="FindPEntityRefs" attribute="Other Text" lineEndContext="#stay"> <RegExpr attribute="EntityRef" context="#stay" String="&entref;" /> <RegExpr attribute="PEntityRef" context="#stay" String="%&name;;" /> <AnyChar attribute="Error" context="#stay" String="&%" /> </context> <context name="FindAttributes" attribute="Other Text" lineEndContext="#stay"> <RegExpr attribute="Attribute" context="#stay" String="&name;" column="0"/> <RegExpr attribute="Attribute" context="#stay" String="\s+&name;" /> <DetectChar attribute="Attribute" context="Value" char="=" /> </context> <context name="FindDTDRules" attribute="Other Text" lineEndContext="#stay"> <RegExpr attribute="Doctype" context="Doctype Markupdecl" String="<!(ELEMENT|ENTITY|ATTLIST|NOTATION)\b" /> </context> <context name="Comment" attribute="Comment" lineEndContext="#stay"> <DetectSpaces/> <IncludeRules context="##Alerts" /> <DetectIdentifier/> <StringDetect attribute="Comment" context="#pop" String="-->" endRegion="comment" /> <RegExpr attribute="Error" context="#stay" String="-(-(?!->))+" /> </context> <context name="Commenttmpl" attribute="Commenttmpl" lineEndContext="#stay"> <DetectSpaces/> <DetectIdentifier/> <StringDetect attribute="Commenttmpl" context="#pop" String="%>" endRegion="commenttmpl" /> </context> <context name="CDATA" attribute="Other Text" lineEndContext="#stay"> <DetectSpaces/> <DetectIdentifier/> <StringDetect attribute="CDATA" context="#pop" String="]]>" endRegion="cdata" /> <StringDetect attribute="EntityRef" context="#stay" String="]]&gt;" /> </context> <context name="PI" attribute="Other Text" lineEndContext="#stay"> <Detect2Chars attribute="Processing Instruction" context="#pop" char="?" char1=">" endRegion="pi" /> </context> <context name="Doctype" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Doctype" context="#pop" char=">" endRegion="doctype" /> <DetectChar attribute="Doctype" context="Doctype Internal Subset" char="[" beginRegion="int_subset" /> </context> <context name="Doctype Internal Subset" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Doctype" context="#pop" char="]" endRegion="int_subset" /> <IncludeRules context="FindDTDRules" /> <StringDetect attribute="Comment" context="Comment" String="<!--" beginRegion="comment" /> <RegExpr attribute="Processing Instruction" context="PI" String="<\?[\w:-]*" beginRegion="pi" /> <IncludeRules context="FindPEntityRefs" /> </context> <context name="Doctype Markupdecl" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Doctype" context="#pop" char=">" /> <DetectChar attribute="Value" context="Doctype Markupdecl DQ" char=""" /> <DetectChar attribute="Value" context="Doctype Markupdecl SQ" char="'" /> </context> <context name="Doctype Markupdecl DQ" attribute="Value" lineEndContext="#stay"> <DetectChar attribute="Value" context="#pop" char=""" /> <IncludeRules context="FindPEntityRefs" /> </context> <context name="Doctype Markupdecl SQ" attribute="Value" lineEndContext="#stay"> <DetectChar attribute="Value" context="#pop" char="'" /> <IncludeRules context="FindPEntityRefs" /> </context> <context name="El Open" attribute="Other Text" lineEndContext="#stay"> <Detect2Chars attribute="Element" context="#pop" char="/" char1=">" /> <DetectChar attribute="Element" context="#pop" char=">" /> <IncludeRules context="FindAttributes" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="El Close" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Element" context="#pop" char=">" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="El Close 2" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Element" context="#pop#pop#pop" char=">" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="El Close 3" attribute="Other Text" lineEndContext="#stay"> <DetectChar attribute="Element" context="#pop#pop#pop#pop" char=">" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="CSS" attribute="Other Text" lineEndContext="#stay"> <Detect2Chars attribute="Element" context="#pop" char="/" char1=">" endRegion="style" /> <DetectChar attribute="Element" context="CSS content" char=">" /> <IncludeRules context="FindAttributes" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="CSS content" attribute="Other Text" lineEndContext="#stay"> <RegExpr attribute="Element" context="El Close 2" String="</style\b" insensitive="TRUE" endRegion="style" /> <IncludeRules context="##CSS" includeAttrib="true"/> </context> <context name="JS" attribute="Other Text" lineEndContext="#stay"> <Detect2Chars attribute="Element" context="#pop" char="/" char1=">" endRegion="script" /> <DetectChar attribute="Element" context="JS content" char=">" /> <IncludeRules context="FindAttributes" /> <RegExpr attribute="Error" context="#stay" String="\S" /> </context> <context name="JS content" attribute="Other Text" lineEndContext="#stay"> <RegExpr attribute="Element" context="El Close 2" String="</script\b" insensitive="TRUE" endRegion="script" /> <RegExpr attribute="Comment" context="JS comment close" String="//(?=.*</script\b)" insensitive="TRUE" /> <IncludeRules context="##JavaScript" includeAttrib="true"/> </context> <context name="JS comment close" attribute="Comment" lineEndContext="#pop"> <RegExpr attribute="Element" context="El Close 3" String="</script\b" insensitive="TRUE" endRegion="script" /> <IncludeRules context="##Alerts" /> </context> <context name="Value" attribute="Other Text" lineEndContext="#stay" fallthrough="true" fallthroughContext="Value NQ"> <DetectChar attribute="Value" context="Value DQ" char=""" /> <DetectChar attribute="Value" context="Value SQ" char="'" /> <DetectSpaces /> </context> <context name="Value NQ" attribute="Other Text" lineEndContext="#pop#pop" fallthrough="true" fallthroughContext="#pop#pop"> <IncludeRules context="FindEntityRefs" /> <RegExpr attribute="Value" context="#stay" String="/(?!>)" /> <RegExpr attribute="Value" context="#stay" String="[^/><"'\s]" /> </context> <context name="Value DQ" attribute="Value" lineEndContext="#stay"> <DetectChar attribute="Value" context="#pop#pop" char=""" /> <IncludeRules context="FindEntityRefs" /> </context> <context name="Value SQ" attribute="Value" lineEndContext="#stay"> <DetectChar attribute="Value" context="#pop#pop" char="'" /> <IncludeRules context="FindEntityRefs" /> </context> </contexts> <itemDatas> <itemData name="Normal Text" defStyleNum="dsNormal" /> <itemData name="Other Text" defStyleNum="dsNormal" spellChecking="false" /> <itemData name="Comment" defStyleNum="dsComment" /> <itemData name="Commenttmpl" defStyleNum="dsComment" color="#66f" /> <itemData name="CDATA" defStyleNum="dsBaseN" bold="1" spellChecking="false" /> <itemData name="Processing Instruction" defStyleNum="dsKeyword" spellChecking="false" /> <itemData name="Doctype" defStyleNum="dsDataType" bold="1" spellChecking="false" /> <itemData name="Element" defStyleNum="dsKeyword" spellChecking="false" /> <itemData name="Attribute" defStyleNum="dsOthers" spellChecking="false" /> <itemData name="Value" defStyleNum="dsString" color="#a00" spellChecking="false" /> <itemData name="EntityRef" defStyleNum="dsDecVal" spellChecking="false" /> <itemData name="PEntityRef" defStyleNum="dsDecVal" spellChecking="false" /> <itemData name="Error" defStyleNum="dsError" spellChecking="false" /> </itemDatas> </highlighting> <general> <comments> <comment name="multiLine" start="<!--" end="-->" /> </comments> </general> </language> 



Now we will start

Depending on the construction should be added:

 LIBS += -L/usr/local/lib/ -lbooster -lcppcms INCLUDEPATH += /usr/local/include DEPENDPATH += /usr/local/include 


Create a file main.cpp and fill it with the following contents:

 #include <cppcms/applications_pool.h> #include <cppcms/url_dispatcher.h> #include <cppcms/http_response.h> #include <cppcms/application.h> #include <cppcms/url_mapper.h> #include <cppcms/service.h> //------------------------------------------------------------------------------------- // Dsc:    ,      //       //------------------------------------------------------------------------------------- class WebSite : public cppcms::application{ public: //------------------------------------------------------------------------------------- // Dsc: ,        //------------------------------------------------------------------------------------- WebSite(cppcms::service &s) : cppcms::application(s) {} //------------------------------------------------------------------------------------- // Dsc:     ,       // (    ) //------------------------------------------------------------------------------------- virtual void main(std::string path) { response().out() << "Hello!"; } }; //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- int main(int argc,char **argv) { try { //   cppcms::service srv(argc,argv); //   srv.applications_pool().mount(cppcms::applications_factory<WebSite>()); //  srv.run(); } catch(std::exception const &e) { std::cerr << "Failed: " << e.what() << std::endl; std::cerr << booster::trace(e) << std::endl; return 1; } return 0; } 


If you have already tried to start it, then most likely nothing happened, because to complete the work there is not enough configuration file for the server, its location must be transferred to the binary at startup.
WebApp.bin -c config.json
The config may be as follows:
 { "WebSite" : { "root" : "", "host" : "localhost:8080", "locdomain" : "localhost", }, "service" : { "ip" : "0.0.0.0", "api" : "http", "port" : 8080 }, "http" : { "script" : "/mb.fcgi" , "rewrite" : [ { "regex" : ".*" , "pattern" : "/mb.fcgi$0" } ], } } 

That should be enough.
It is also a good option to register the launch parameter in the “programming environment configs”
So, append and run and open.

Impressive? Not?
This is true, since for this example we did not use the template mechanism, but limited ourselves to a banal string output. However, the example allows us to make sure that everything works.

Use of templates


Let's write the first template that will be “turned” by the library template engine into a * .cpp file.
So, first of all, add a header file containing the structure of dynamic data (template data). By default, they will be placed in the data folder inside the project.
data / tmpl_master.h
 #ifndef TMPL_MASTER_H #define TMPL_MASTER_H #include <cppcms/view.h> namespace Data { //------------------------------------------------------------------------------------- // Dsc:      //------------------------------------------------------------------------------------- struct infoPage { std::string title; //   std::string description; //   std::string keywords; //    std::map<std::string,std::string> menuList; //     (url,desc) //------------------------------------------------------------------------------------- // Dsc: ,   //------------------------------------------------------------------------------------- infoPage() : title (""), description(""), keywords (""), menuList ( ) {} //------------------------------------------------------------------------------------- // Dsc: ,    //------------------------------------------------------------------------------------- ~infoPage(){} }; //------------------------------------------------------------------------------------- // Dsc:        //------------------------------------------------------------------------------------- struct Master :public cppcms::base_content { infoPage page; //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- Master() : page() {} //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- ~Master(){} }; } #endif 


The content of this file is usually not distinguished by any clever code, and in fact it is just containers for describing variables used in templates.

Let's start writing the actual template, create a templates folder with the master.tmpl file in it, with the following contents:
 <% c++ #include "data/tmpl_master.h" %> <% skin defskin %> <% view Master uses Data::Master %> <% template page_main() %>MAIN TEMPLATE<% end %> <% template page_footer() %>  <% end %> <% template page_left_sidebar() %> <% end %> <% template render() %> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title><%= page.title %></title> <meta name="keywords" content="<%= page.keywords %>" /> <meta name="description" content="<%= page.description %>" /> <link href="/media/css/style.css" rel="stylesheet"> </head> <body> <div class="wrapper"> <header class="header"> <div class="nav" > <% foreach menuItem in page.menuList %> <ul> <% item %> <li><a href="<%= menuItem.first %>"><%= menuItem.second %></a></li> <% end %> </ul> <% end %> </div> </header> <div class="middle"> <div class="container"> <main class="content"><% include page_main() %></main> </div> <aside class="left-sidebar"> <div> <% include page_left_sidebar() %> </div> </aside> </div> </div> <footer class="footer"><% include page_footer() %></footer> </body> </html> <% end template %> <% end view %> <% end skin %> 

What is written here?
In the very first line of <% c++ #include "data/tmpl_master.h" %> we write a header file in which our data structures will be declared.
The <% skin defskin %> defines the name of the current skin, that is, you may have different displays for the site pages.
The string <% view Master uses Data::Master %> defines the name of the current template as “Master” (Later we will specify it for the page filling mechanism), as well as create the Data :: Master structure inside the wrapper class. What does being translated into c ++ look like “Data :: Master context;” (if you are interested in details, you can always see the generated file)
Rows <% template page_main() %>MAIN TEMPLATE<% end %>
<% template page_footer() %> <% end %>
<% template page_left_sidebar() %> <% end %>
<% template page_main() %>MAIN TEMPLATE<% end %>
<% template page_footer() %> <% end %>
<% template page_left_sidebar() %> <% end %>

define default values ​​that will be displayed to the user if we do not override them (that is, are
 virtual const char* page_main(){ return "MAIN TEMPLATE"; } 
so probably clearer. ).
Let's try to collect. It's clear that the compiler with ++ will not swallow the tmpl file. Therefore, the utility that comes together with the library, which rework the template to the desired state, should come to the rescue.
To do this, create a file “make_templates.sh” inside the project, inside which we place the operations we need (This file can be easily replaced either by manually calling this utility or writing it in the “executable part” of your environment):

 #!/bin/bash INPUT="" OUTPUT="" while getopts ":i:o:" opt; do case $opt in i) INPUT=$OPTARG ;; o) OUTPUT=$OPTARG ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done #       cp $INPUT/config.json $OUTPUT #     TEMPLATES="$INPUT/templates/master.tmpl" #    - cppcms_tmpl_cc $TEMPLATES -o $INPUT/all_tmpl.cpp #     g++ -shared -fPIC $INPUT/all_tmpl.cpp -o $OUTPUT/libcpp_defskin.so -lcppcms -lbooster 


Now in the settings of the QtCreator project you need to add a “custom step”
Command: "./make_templates.sh"
Working directory: "% {sourceDir}"
Command Arguments: "-i% {sourceDir} -o% {buildDir}"
Do not forget to add the file "executable."

If the build is successful, then the libcpp_defskin.so library will appear in the build directory as well.
It is important to note that you can build a library statically or dynamically. I have done the second method, I strongly advise you not to use the first one, since the TMPL files have to be changed often, and because of this, the whole project is recompiled, and it is a very ungrateful task.

Also, that the templates would be tied to the project - you need to add the file config.json
 { "WebSite" : { "root" : "", "host" : "localhost:8080", "locdomain" : "localhost", }, "service" : { "ip" : "0.0.0.0", "api" : "http", "port" : 8080 }, "http" : { "script" : "/mb.fcgi" , "rewrite" : [ { "regex" : "/media(/.+)", "pattern" : "$1" }, { "regex" : ".*" , "pattern" : "/mb.fcgi$0" } ], }, "views" : { "default_skin" : "defskin" , "paths" : [ "./" ], "skins" : [ "cpp_defskin" ], }, } 


And make the appropriate changes to main.cpp:
 #include "data/tmpl_master.h" ... WebSite::main(std::string path) { Data::Master tmpl; tmpl.page.title = path; tmpl.page.description = "description"; tmpl.page.keywords = "keywords"; tmpl.page.menuList.insert(std::pair<std::string,std::string>("/","MAIN")); tmpl.page.menuList.insert(std::pair<std::string,std::string>("/else","ELSE")); render("Master",tmpl); } 


Now when starting the project, we should see the template output. But wait, I completely forgot about css and images, now I'll fix it.
Add another item to config.json
  "file_server" : { "enable" : true, "listing" : true, "document_root" : "./media" }, 

Here we definitely need to clarify that with this item we allow the binary to look into the file system. And the rules by which he does this are described in the section http { "regex" : "/media(/.+)", "pattern" : "$1" },
that is, any request starting with / media / should be redirected to the “file server”.
Create a media folder in the project folder, and also add the corresponding item to make_templates.sh:
 #       cp -R $INPUT/media $OUTPUT 

Inside the media folder (in the source directory of the project) create a subfolder css, and in it the file style.css
Hidden text
 /* Eric Meyer's CSS Reset */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } /* End of Eric Meyer's CSS Reset */ html { height: 100%; } article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } body { font: 12px/18px Arial, sans-serif; width: 100%; height: 100%; } .wrapper { width: 800px; margin: 0 auto; min-height: 100%; height: auto !important; height: 100%; } /* Header -----------------------------------------------------------------------------*/ .header { height: 50px; background: #FFE680; } /* Middle -----------------------------------------------------------------------------*/ .middle { width: 100%; padding: 0 0 50px; position: relative; } .middle:after { display: table; clear: both; content: ''; } .container { width: 100%; float: left; overflow: hidden; } .content { padding: 0 270px 0 270px; } /* Left Sidebar -----------------------------------------------------------------------------*/ .left-sidebar { float: left; width: 250px; margin-left: -100%; position: relative; background: #B5E3FF; } /* Footer -----------------------------------------------------------------------------*/ .footer { width: 800px; margin: -50px auto 0; height: 50px; background: #BFF08E; position: relative; } 


We try to collect again.
Now, when the site is similar to the first work of a novice master - you can go to the most important thing.

Pattern Inheritance


The template inheritance mechanism is extremely simple. We determine from which template we inherit and append the redefinition of the content output function.
Create a file file tmpl_news.h in the data folder
 #ifndef TMPL_NEWS_H #define TMPL_NEWS_H #include "tmpl_master.h" namespace Data { //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- struct News :public Master{ //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- std::string mainNews; //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- News() : Master() {} //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- ~News(){} }; } #endif // TMPL_NEWS_H 


Also add the news.tmpl file to the templates folder
 <% c++ #include "data/tmpl_news.h" %> <% skin defskin %> <% view News uses Data::News extends Master %> <% template page_main() %><%= mainNews %><% end %> <% end view %> <% end skin %> 

Add the path to the file to the build script (it should look something like this):

 TEMPLATES="$INPUT/templates/master.tmpl" TEMPLATES="$TEMPLATES $INPUT/templates/news.tmpl" 


Modify the main.cpp file
 #include <cppcms/applications_pool.h> #include <cppcms/url_dispatcher.h> #include <cppcms/http_response.h> #include <cppcms/application.h> #include <cppcms/url_mapper.h> #include <cppcms/service.h> #include "data/tmpl_master.h" #include "data/tmpl_news.h" //------------------------------------------------------------------------------------- // Dsc:    ,      //       //------------------------------------------------------------------------------------- class WebSite : public cppcms::application{ public: //------------------------------------------------------------------------------------- // Dsc: ,        //------------------------------------------------------------------------------------- WebSite(cppcms::service &s) : cppcms::application(s) { dispatcher().assign("/news(.*)",&WebSite::news,this,1); mapper().assign("news","/news"); dispatcher().assign("(/?)",&WebSite::master,this,1); mapper().assign("master","/"); } //------------------------------------------------------------------------------------- // Dsc:     ,       // (    ) //------------------------------------------------------------------------------------- virtual void main(std::string path) { cppcms::application::main(path); } //------------------------------------------------------------------------------------- // Dsc:    //------------------------------------------------------------------------------------- virtual void master(std::string path) { Data::Master tmpl; tmpl.page.title = path; tmpl.page.description = "description"; tmpl.page.keywords = "keywords"; tmpl.page.menuList.insert(std::pair<std::string,std::string>("/","MASTER")); tmpl.page.menuList.insert(std::pair<std::string,std::string>("/news","NEWS")); render("Master",tmpl); } //------------------------------------------------------------------------------------- // Dsc:   //------------------------------------------------------------------------------------- virtual void news(std::string path) { Data::News tmpl; tmpl.page.title = path; tmpl.page.description = "description"; tmpl.page.keywords = "keywords"; tmpl.page.menuList.insert(std::pair<std::string,std::string>("/","MASTER")); tmpl.page.menuList.insert(std::pair<std::string,std::string>("/news","NEWS")); tmpl.mainNews = "!       !"; render("News",tmpl); } }; //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- int main(int argc,char **argv) { try { //   cppcms::service srv(argc,argv); //   srv.applications_pool().mount(cppcms::applications_factory<WebSite>()); //  srv.run(); } catch(std::exception const &e) { std::cerr << "Failed: " << e.what() << std::endl; std::cerr << booster::trace(e) << std::endl; return 1; } return 0; } } 

The main changes in the file occurred in the constructor, where we indicated which function is responsible for the output of which page.
Now these pages display various templates.
A particularly important point is the order in which the file list is submitted to the template engine (descendant files must follow the parents, otherwise errors will occur).

On this I plan to finish the first part.

Source: https://habr.com/ru/post/219899/


All Articles