Thread: [Cppcms-users] Plugins, Localization, script_names, url mapper
Brought to you by:
artyom-beilis
From: Raab M. <Mar...@ka...> - 2012-03-02 10:11:16
|
Hi Artyom! In the first example of the plugin interface you pass the application pointer to the plugin. I think it would be more decoupled if the plugin could create its own stripped down application just for rendering. Btw. the functions rendering to a stream should be const, or do they modify the application? That change would however break the API.. Is there any approach how to get booster::locale working Inside own plugins? Is it possible with the integrated webserver to have the script at /? If "script_names" is set to "/", the url is localhost//name. If it is not given or "", I always get 404 for every url. Is it possible to reconfigure the internal file server to be at another root? I am afraid I do not fully understand the url mapper. E.g. I have: 27 attach (new Base_gui(srv), 28 "gui", "/gui{1}", 29 "/gui(/(.*))?", 1); 30 31 attach (new Base_rpc(srv), 32 "rpc", "/rpc{1}", 33 "/rpc(/(.*))?", 1); For any reason 52 << "<a href='" << url("gui")<< "'>GUI</a><br>" 53 << "<a href='" << url("rpc")<< "'>RPC</a><br> works for gui, but not for rpc? See following error for rpc: 2012-03-01 15:46:48; cppcms, error: url_mapper: key `' not found for url `gui' 0x4056a414: booster::stack_trace::trace(void**, int) + 0x24 in /usr/lib/libbooster.so.0 0x400ef4b9: cppcms::cppcms_error::cppcms_error(std::string const&) + 0x89 in /usr/lib/libcppcms.so.1 0x4012c007: cppcms::url_mapper::data::get_entry(cppcms::string_key const&, unsigned int, cppcms::string_key const&) const + 0x277 in /usr/lib/libcppcms.so.1 0x4012d587: cppcms::url_mapper::data::map(cppcms::string_key const&, cppcms::string_key const&, cppcms::filters::streamable const* const*, unsigned int, std::map<cppcms::string_key, std::string, std::less<cppcms::string_key>, std::allocator<std::pair<cppcms::string_key const, std::string> > > const&, std::map<cppcms::string_key, std::string, std::less<cppcms::string_key>, std::allocator<std::pair<cppcms::string_key const, std::string> > > const&, std::ostream&) const + 0x37 in /usr/lib/libcppcms.so.1 0x4012a02c: cppcms::url_mapper::real_map(char const*, cppcms::filters::streamable const* const*, unsigned int, std::ostream&) + 0x7dc in /usr/lib/libcppcms.so.1 0x4012ab6b: cppcms::url_mapper::map(std::ostream&, char const*) + 0x3b in /usr/lib/libcppcms.so.1 0x4012abad: cppcms::url_mapper::map(std::ostream&, std::string const&) + 0x2d in /usr/lib/libcppcms.so.1 0x40122384: cppcms::application::url(std::string const&) + 0x1f4 in /usr/lib/libcppcms.so.1 0x80506c3: AMT::Base::describe() + 0x243 in /home/markus/CVP/svn/cvp/trunk/software/cpu/build/bin/webserver 0x8051f7d: booster::function<void ()()>::callable_impl<void, cppcms::url_dispatcher::binder0<AMT::Base> >::call() + 0x2d in /home/markus/CVP/svn/cvp/trunk/software/cpu/build/bin/webserver 0x40123a2c: ??? + 0x40123a2c in /usr/lib/libcppcms.so.1 0x401238c0: cppcms::url_dispatcher::dispatch(std::string) + 0x90 in /usr/lib/libcppcms.so.1 0x4011eb43: cppcms::application::main(std::string) + 0x43 in /usr/lib/libcppcms.so.1 0x401175aa: cppcms::http::context::dispatch(booster::intrusive_ptr<cppcms::application>, std::string, bool) + 0x7a in /usr/lib/libcppcms.so.1 0x40119238: booster::function<void ()()>::callable_impl<void, cppcms_boost::_bi::bind_t<void, void (*)(booster::intrusive_ptr<cppcms::application>, std::string, bool), cppcms_boost::_bi::list3<cppcms_boost::_bi::value<booster::intrusive_ptr<cppcms::application> >, cppcms_boost::_bi::value<std::string>, cppcms_boost::_bi::value<bool> > > >::call() + 0x68 in /usr/lib/libcppcms.so.1 0x4011b027: cppcms::impl::thread_pool::worker() + 0xa7 in /usr/lib/libcppcms.so.1 0x4011ad5e: booster::function<void ()()>::callable_impl<void, cppcms_boost::_bi::bind_t<void, cppcms_boost::_mfi::mf0<void, cppcms::impl::thread_pool>, cppcms_boost::_bi::list1<cppcms_boost::_bi::value<cppcms::impl::thread_pool*> > > >::call() + 0x1e in /usr/lib/libcppcms.so.1 0x405bd41a: booster_thread_func + 0x2a in /usr/lib/libbooster.so.0 0x405e6955: ??? + 0x405e6955 in /lib/i686/cmov/libpthread.so.0 0x4049f5ee: clone + 0x5e in /lib/i686/cmov/libc.so.6 Sorry for all topics in one mail. Best regards Markus Raab The information contained in this e-mail message is privileged and confidential and is for the exclusive use of the addressee. The person who receives this message and who is not the addressee, one of his employees or an agent entitled to hand it over to the addressee, is informed that he may not use, disclose or reproduce the contents thereof, and is kindly asked to notify the sender and delete the e-mail immediately. |
From: Artyom B. <art...@ya...> - 2012-03-02 18:12:39
|
> > In the first example of the plugin interface you pass > the application pointer to the plugin. I think it > would be more decoupled if the plugin could create > its own stripped down application just for rendering. It is up to you, really. I just had shown the general concept how it can be done. > Btw. the functions rendering to a stream should be > const, or do they modify the application? That change > would however break the API.. > It is not const. Because when you call render to access response().out() that does many things under the hood. So even thou technically it may be const. Semantically it does not have to. > Is there any approach how to get booster::locale working > Inside own plugins? > No problem: 1. All applications that are build in hierarchy share same http::context() that holds the locale, 2. Also the response().out() stream has std::locale imbued inside it. That is why you can call for example <% gt ... %> from the view. Of course if you render to your own std::ostream then you should imbue the std::locale object. my_stream.imbue(context().locale()); But it is better to use <% render ... %> template to render the plugin's view, this way you don\t use intermediate buffers and render to the same ostream. > Is it possible with the integrated webserver to > have the script at /? If "script_names" is set to "/", > the url is localhost//name. If it is not given or "", > I always get 404 for every url. > Yes: http://cppcms.com/wikipp/en/page/run_application_web_server_root Specifically: http://cppcms.com/wikipp/en/page/run_application_web_server_root#CppCMS-Embedded > Is it possible to reconfigure the internal file server > to be at another root? You mean "document root"? Yes: http://cppcms.com/wikipp/en/page/cppcms_1x_config#file_server.document_root Also you may be interested in aliases: http://cppcms.com/wikipp/en/page/cppcms_1x_config#file_server.alias > > I am afraid I do not fully understand the url mapper. > E.g. I have: > > 27 attach (new Base_gui(srv), > 28 "gui", "/gui{1}", > 29 "/gui(/(.*))?", 1); > 30 > 31 attach (new Base_rpc(srv), > 32 "rpc", "/rpc{1}", > 33 "/rpc(/(.*))?", 1); > > > For any reason > > 52 << "<a href='" << > url("gui")<< "'>GUI</a><br>" > 53 << "<a href='" << > url("rpc")<< "'>RPC</a><br> > > works for gui, but not for rpc? See following error for rpc: > > 2012-03-01 15:46:48; cppcms, error: url_mapper: key `' not found for url > `gui' > > [...] > > Sorry for all topics in one mail. > Best regards > > Markus Raab > Because when you map sub-application and refer to it you automatically referred to the default URL of the sub-application - empty one "empty key" See: http://cppcms.com/cppcms_ref/latest/classcppcms_1_1url__mapper.html#a249e59de419f7fd0241cab6634c68393 Also I'd recommend to update to CppCMS 1.0.0 as in latest version exception is not thrown in case of invalid URL but rather "/this_is_invalid_url" some something like that generated. Regards, Artyom |
From: Markus R. <us...@ma...> - 2012-03-06 16:05:01
|
Hi! Thanks for your detailed answer. Artyom Beilis wrote: >> In the first example of the plugin interface you pass >> the application pointer to the plugin. I think it >> would be more decoupled if the plugin could create >> its own stripped down application just for rendering. > > It is up to you, really. > > I just had shown the general concept how it can be > done. Yes, there are of course different requirements on how plugins should work. >> Btw. the functions rendering to a stream should be >> const, or do they modify the application? That change >> would however break the API.. >> > > It is not const. Because when you call render to access > response().out() that does many things under the hood. > > So even thou technically it may be const. Semantically > it does not have to. > >> Is there any approach how to get booster::locale working >> Inside own plugins? >> > > No problem: > > 1. All applications that are build in hierarchy > share same http::context() that holds the locale, > > 2. Also the response().out() stream has std::locale > imbued inside it. That is why you can call > for example <% gt ... %> from the view. > > Of course if you render to your own std::ostream > then you should imbue the std::locale object. > > my_stream.imbue(context().locale()); That is working. I was asking myself how the booster::locale::translate is working within plugins. In the main program translate() is working, but not in the plugins. I did not called std::locale::global(gen("")); > But it is better to use <% render ... %> template > to render the plugin's view, this way you don\t use > intermediate buffers and render to the same ostream. The advantage of using a own buffer to render is that it is completely up to the plugins if they want to use cppcms rendering at all. They might directly stream the text, e.g. for error pages or where templates are overkill. But if it does not work well - see problem below - I may change to use render() template. I do not understand the "With the command render" example: In std::string main_html(cppcms::applicatin *app) the plugin still renders to a buffer and returs the string, so what is the difference? The problem I currently have with the streaming to buffer is when having a form and requesting the POST data within the plugin. E.g. I have the following code: 17 void My_plugin::do(std::ostream & buf, cppcms::application & app) 18 { 19 if(app.request().request_method()=="POST") 20 { 21 m_main.m_form.load(app.context()); 22 m_main.m_form.validate(); 23 ::std::cout << "x is: " << m_main.m_form.x.value() << std::endl; 24 m_main.m_form.clear(); 25 } 26 27 app.render("plugin_skin","main_html",buf,m_main); 28 } Then I get following exception: 2012-03-06 09:52:08; cppcms, error: Caught exception [Value was not loaded] 0x40566414: booster::stack_trace::trace(void**, int) + 0x24 in /usr/lib/libbooster.so.0 0x4015fe9b: cppcms::widgets::base_text::value() + 0xcb in /usr/lib/libcppcms.so.1 0x43132180: My_plugin::do(std::ostream&, cppcms::application&) in line 23 >> Is it possible with the integrated webserver to >> have the script at /? If "script_names" is set to "/", >> the url is localhost//name. If it is not given or "", >> I always get 404 for every url. >> > > Yes: > > http://cppcms.com/wikipp/en/page/run_application_web_server_root > > > Specifically: > > http://cppcms.com/wikipp/en/page/run_application_web_server_root#CppCMS- Embedded Works perfectly, thanks! >> Is it possible to reconfigure the internal file server >> to be at another root? > > You mean "document root"? > > Yes: > > http://cppcms.com/wikipp/en/page/cppcms_1x_config#file_server.document_root No, I mean the root where the internal file server application is mounted to. But it seems to be hardcoded with "" in line 238: applications_pool().mount(applications_factory<cppcms::impl::file_server>(),mount_point("")); > Also you may be interested in aliases: > > http://cppcms.com/wikipp/en/page/cppcms_1x_config#file_server.alias Yeah, that seems to solve the issue. Is there some explanation how this works if multiple applications are mounted at the same root? >> I am afraid I do not fully understand the url mapper. >> E.g. I have: >> >> 27 attach (new Base_gui(srv), >> 28 "gui", "/gui{1}", >> 29 "/gui(/(.*))?", 1); >> 30 >> 31 attach (new Base_rpc(srv), >> 32 "rpc", "/rpc{1}", >> 33 "/rpc(/(.*))?", 1); >> >> >> For any reason >> >> 52 << "<a href='" << >> url("gui")<< "'>GUI</a><br>" >> 53 << "<a href='" << >> url("rpc")<< "'>RPC</a><br> >> >> works for gui, but not for rpc? See following error for rpc: >> >> 2012-03-01 15:46:48; cppcms, error: url_mapper: key `' not found for url >> `gui' > > Because when you map sub-application and refer to it > you automatically referred to the default URL > of the sub-application - empty one "empty key" Sorry, I do not understand this statement. There are some examples for mapper and dispatcher, but I can't find anything related to how the url() call works. Doxygen just says: "Map url-key key to actual URL, without parameters" What does url("gui") does? Can I use mapper().set_value? I think copy&paste of how wikipp does + explanation would help, because the redirecting + url resolving there is what most users want anyway. > See: > > http://cppcms.com/cppcms_ref/latest/classcppcms_1_1url__mapper.html#a249e59de419f7fd0241cab6634c68393 "Map the default key for the application, url has same rules as for assign(key,url) but they rather refer to default application's URL when it is used in hierarchy. " does not help much either > Also I'd recommend to update to CppCMS 1.0.0 as in latest > version exception is not thrown in case of invalid URL but > rather "/this_is_invalid_url" some something like that generated. Done :-) But I still get http://localhost:10000/this_is_an_invalid_url_generated_by_url_mapper best regards Markus |
From: Artyom B. <art...@ya...> - 2012-03-06 21:06:06
|
>> >> my_stream.imbue(context().locale()); > >That is working. > >I was asking myself how the booster::locale::translate is working within >plugins. In the main program translate() is working, but not in the plugins. >I did not called std::locale::global(gen("")); > See: stream << booster::locale::translate("foo") Works because actual translation is postponed to the stage were the data is written to the stream and rendered withing it. booster::locale::translate-> booster::locale::message + std::ostream's locale gives translation. So if you want to use locale for your plugin you need to have some locale context. It can be done by std::string translated = app.translate("foo"); or use locale explicitly as: std::locale loc = app.context().locale(); std::string translated = booster::locale::translate("foo").str(loc); or std::locale loc = app.context().locale(); std::string translated = booster::locale::gettext("foo",loc); Of course if your application uses only one language globally you can just set std::locale::global. > >But if it does not work well - see problem below - I may change to use >render() template. I do not understand the "With the command render" >example: In std::string main_html(cppcms::applicatin *app) the plugin still >renders to a buffer and returs the string, so what is the difference? > It was just an example However, if you call <% render ... %> from the view it renders to the output stream without intermediate buffers. >E.g. I have the following code: > >17 void My_plugin::do(std::ostream & buf, cppcms::application & app) >18 { >19 if(app.request().request_method()=="POST") >20 { >21 m_main.m_form.load(app.context()); >22 m_main.m_form.validate(); >23 ::std::cout << "x is: " << m_main.m_form.x.value() << >std::endl; >24 m_main.m_form.clear(); >25 } >26 >27 app.render("plugin_skin","main_html",buf,m_main); >28 } > >Then I get following exception: >2012-03-06 09:52:08; cppcms, error: Caught exception [Value was not loaded] >0x40566414: booster::stack_trace::trace(void**, int) + 0x24 in >/usr/lib/libbooster.so.0 >0x4015fe9b: cppcms::widgets::base_text::value() + 0xcb in >/usr/lib/libcppcms.so.1 >0x43132180: My_plugin::do(std::ostream&, cppcms::application&) in line 23 > I think you had not added m_form.x to m_form (using m_form.add(x)); so when you access x.value() it appears not to be loaded when you call load(app.context()); > > Is there some explanation how this works if multiple applications are > mounted at the same root? The behavior is undefined for `cppcms::application_pool` Generally the first one will be selected, but non necessary, it may be changed in future. So you should provide mutually exclusive mount points. The dispatching and matching withing application (url_dispatched) is done according to the order of adding them to url_dispatcher. >> >> Because when you map sub-application and refer to it >> you automatically referred to the default URL >> of the sub-application - empty one "empty key" > >Sorry, I do not understand this statement. > First of all take a look on this tutorial carefully. http://cppcms.com/wikipp/en/page/cppcms_1x_tut_hierarchy >There are some examples for mapper and dispatcher, but I can't find anything >related to how the url() call works. >Doxygen just says: "Map url-key key to actual URL, without parameters" >What does url("gui") does? > application::url() and <% url ... %> is a family of functions with variable number of parameters. when you call url("foo") it looks for the object named "foo" If it is actual function (not sub application) it provides a url if it is subapplication it tries to dispatch the "" key. See, applications are generated in the hierary, so For given application: foo, sub application bar and bar's method baz url("/foo/bar/baz") would map to the "baz"'s url. url("/foo/bar") would map to default (empty) url of baz application. You can have parameters as well for example // withing bar mapper().assign("baz","/baz"); mapper().assign("baz","/baz/{1}"); mapper().assign("baz","/baz/{1}/{2}"); Then you can call: url("/foo/bar/baz") -> something/baz url("/foo/bar/baz",20) -> something/baz/20 url("/foo/bar/baz","x","y") -> something/baz/x/y >Can I use mapper().set_value? > > set_value should be used for some horizontal parameters like for example language when you want to change the URL independently from, the hierary. mapper().set_value("lang","en") url("/foo/bar") -> en.wiki.org/foo/bar url("/baz") -> en.wiki.org/baz mapper().set_value("lang","he") url("/foo/bar") -> he.wiki.org/foo/bar url("/baz") -> he.wiki.org/baz >I think copy&paste of how wikipp does + explanation would help, because the >redirecting + url resolving there is what most users want anyway. > Actually, wikipp was written before URL-mapper existed and I had no time to update it. Take a look rather on the cppcms's blog it uses url mapper fully. Regards, Artyom Beilis, P.S.: URL Mapper/Dispatcher is actually not-so simple and powerful part I need to write a better tutorial. |
From: Markus R. <us...@ma...> - 2012-03-07 14:45:35
|
Hi! Thanks for your detailled answer! The problems with the plugin and localization are now resolved, too. Artyom Beilis wrote: >>> my_stream.imbue(context().locale()); >> >>That is working. >> >>I was asking myself how the booster::locale::translate is working within >>plugins. In the main program translate() is working, but not in the >>plugins. I did not called std::locale::global(gen("")); >> > > See: > > stream << booster::locale::translate("foo") > > Works because actual translation is postponed to the > stage were the data is written to the stream and rendered withing it. > > booster::locale::translate-> booster::locale::message + std::ostream's > locale gives translation. > > So if you want to use locale for your plugin you need to have some locale > context. It can be done by > > std::string translated = app.translate("foo"); > > or use locale explicitly as: > > std::locale loc = app.context().locale(); > std::string translated = booster::locale::translate("foo").str(loc); > > > or > > std::locale loc = app.context().locale(); > std::string translated = booster::locale::gettext("foo",loc); > > > Of course if your application uses only one language globally > you can just set std::locale::global. Thanks, I think we now have every option available. I found a method for every problem! >>But if it does not work well - see problem below - I may change to use >>render() template. I do not understand the "With the command render" >>example: In std::string main_html(cppcms::applicatin *app) the plugin >>still renders to a buffer and returs the string, so what is the >>difference? >> > > It was just an example > > However, if you call <% render ... %> from the view it renders to the > output stream without intermediate buffers. My plugin has a print(ostream& ) function and the print() is wrapped in a cppcms::filters::streamable main which is printed by <%= main | raw %>. There should also be no intermediate buffer, or? >>E.g. I have the following code: > >> >>17 void My_plugin::do(std::ostream & buf, cppcms::application & app) >>18 { >>19 if(app.request().request_method()=="POST") >>20 { >>21 m_main.m_form.load(app.context()); >>22 m_main.m_form.validate(); >>23 ::std::cout << "x is: " << m_main.m_form.x.value() << >>std::endl; >>24 m_main.m_form.clear(); >>25 } >>26 >>27 app.render("plugin_skin","main_html",buf,m_main); >>28 } >> >>Then I get following exception: >>2012-03-06 09:52:08; cppcms, error: Caught exception [Value was not >>loaded] 0x40566414: booster::stack_trace::trace(void**, int) + 0x24 in >>/usr/lib/libbooster.so.0 >>0x4015fe9b: cppcms::widgets::base_text::value() + 0xcb in >>/usr/lib/libcppcms.so.1 >>0x43132180: My_plugin::do(std::ostream&, cppcms::application&) in line 23 >> > > I think you had not added m_form.x to m_form (using m_form.add(x)); > so when you access x.value() it appears not to be loaded when you > call load(app.context()); You are completely right! Thanks a lot! I suggest to change the text "Value was not loaded" to something like "The value or the parent was not loaded. Check the hierarchy." ;) >> Is there some explanation how this works if multiple applications are >> mounted at the same root? > > The behavior is undefined for `cppcms::application_pool` Mmmh, but exactly this happens when you use the file server? It is also mounted at "". > Generally the first one will be selected, but non necessary, it > may be changed in future. So you should provide mutually > exclusive mount points. I do not have that situation within my own framework. > The dispatching and matching withing application (url_dispatched) is done > according to the order of adding them to url_dispatcher. Ok, good to know. >>> Because when you map sub-application and refer to it >>> you automatically referred to the default URL >>> of the sub-application - empty one "empty key" >> >>Sorry, I do not understand this statement. >> > > First of all take a look on this tutorial carefully. > > http://cppcms.com/wikipp/en/page/cppcms_1x_tut_hierarchy > > > >>There are some examples for mapper and dispatcher, but I can't find >>anything related to how the url() call works. >>Doxygen just says: "Map url-key key to actual URL, without parameters" > >>What does url("gui") does? >> > > application::url() and <% url ... %> is a family of functions with > variable number of parameters. How does the <% url ... %> using syntax work? Why does <% url "/blog/post" using slug %> resolves to "/myblog/Hi%20%3cyou%3e/" (see http://cppcms.com/wikipp/en/page/cppcms_1x_templates_comm#URL.Mapping) I would rather expect /blog/post/Hi%20%3cyou%3e/? Both <% url "/gui/system" %> <% url "system" %> work without problem, but I could not figure out how to resolve a variable containing "system"? E.g. <% url "/gui/" using menu_element.m_href %> does not work? > when you call url("foo") it looks for the object named "foo" > > If it is actual function (not sub application) it provides a url > > if it is subapplication it tries to dispatch the "" key. Ok, I think I understand the approach now much better. I still can't figure out the details between: url("") url(".") url("/") while the first two seem to be equivalent, url("/") seems to link to the same url where the request() came from? e.g. when I request http://localhost:10000/gui/wrong_url url("/") resolves to http://localhost:10000/gui/wrong_url but url("") and url(".") resolves to ttp://localhost:10000/gui When I use dispatcher().assign("", &GUI::show_error_page, this); mapper().assign("/"); // changed here instead of "" the urls resolve to: url("/") -> http://localhost:10000/gui/wrong_url url(".") -> http://localhost:10000/gui/ url("") -> http://localhost:10000/gui/ So url(".") with assign("/") seems to be what I want ;) > See, applications are generated in the hierary, so > > For given application: foo, sub application bar and bar's method baz > > url("/foo/bar/baz") would map to the "baz"'s url. > > url("/foo/bar") would map to default (empty) url of baz application. > > You can have parameters as well for example > > // withing bar > > mapper().assign("baz","/baz"); > mapper().assign("baz","/baz/{1}"); > mapper().assign("baz","/baz/{1}/{2}"); > > Then you can call: > > url("/foo/bar/baz") -> something/baz > url("/foo/bar/baz",20) -> something/baz/20 > url("/foo/bar/baz","x","y") -> something/baz/x/y Thanks, I think I do not need parameters, because I prefer to have user/browser specific language and not by url. >>Can I use mapper().set_value? >> >> > > set_value should be used for some horizontal parameters > like for example language when you want to change the URL > independently from, the hierary. > > mapper().set_value("lang","en") > url("/foo/bar") -> en.wiki.org/foo/bar > url("/baz") -> en.wiki.org/baz > > mapper().set_value("lang","he") > url("/foo/bar") -> he.wiki.org/foo/bar > url("/baz") -> he.wiki.org/baz Ok, thank you! >>I think copy&paste of how wikipp does + explanation would help, because >>the > >>redirecting + url resolving there is what most users want anyway. >> > > Actually, wikipp was written before URL-mapper existed and I had > no time to update it. Take a look rather on the cppcms's blog > it uses url mapper fully. Ok, so I think the examples you gave in this mail are perfect! > P.S.: URL Mapper/Dispatcher is actually not-so simple and powerful part > I need to write a better tutorial. Yeah, they are powerful, I like them :-) best regards Markus |
From: Artyom B. <art...@ya...> - 2012-03-07 15:25:44
|
>> It was just an example >> >> However, if you call <% render ... %> from the view it renders to the >> output stream without intermediate buffers. > > My plugin has a print(ostream& ) function and the print() is wrapped in a > cppcms::filters::streamable main which is printed by <%= main | raw %>. > There should also be no intermediate buffer, or? > Yep >> I think you had not added m_form.x to m_form (using m_form.add(x)); >> so when you access x.value() it appears not to be loaded when you >> call load(app.context()); > > You are completely right! > Thanks a lot! > I suggest to change the text "Value was not loaded" to something like > "The > value or the parent was not loaded. Check the hierarchy." ;) > Ok... It may not always be the case but I'll take a look on i. >>> Is there some explanation how this works if multiple applications are >>> mounted at the same root? >> >> The behavior is undefined for `cppcms::application_pool` > > Mmmh, but exactly this happens when you use the file server? > It is also mounted at "". > Note, CppCMS HTTP server requires a set of script names that are valid. The invalid script name would be "" - i.e. the script name that could not be found and internal file server is mounted to it. It still uniquely defines it. So do not relay on this behavior, create mutually exclusive mount points. And for most of cases it is better to have one hierarchy and mount entirly different applications to different mount points. I mean if you add a new application it is better to add it as sub-application to the hierarchy then add it to the new mount point. > >>>> Because when you map sub-application and refer to it >>>> you automatically referred to the default URL >>>> of the sub-application - empty one "empty key" >>> >>> Sorry, I do not understand this statement. >>> > > How does the <% url ... %> using syntax work? > > Why does <% url "/blog/post" using slug %> resolves to > "/myblog/Hi%20%3cyou%3e/" > (see http://cppcms.com/wikipp/en/page/cppcms_1x_templates_comm#URL.Mapping) > > I would rather expect /blog/post/Hi%20%3cyou%3e/? > See, it is YOUR urls design, it is rendered the way you define it. You do not have to name applications and URLs the same way (of course it is good idea to be consistent) Remember there is: URL format and Application Hierarchy they do not have to be the same. > Both > <% url "/gui/system" %> > <% url "system" %> > work without problem, but I could not figure out how to resolve a variable > containing "system"? > > E.g. <% url "/gui/" using menu_element.m_href %> does not work? > What do you mean? > >> when you call url("foo") it looks for the object named > "foo" >> >> If it is actual function (not sub application) it provides a url >> >> if it is subapplication it tries to dispatch the "" key. > > Ok, I think I understand the approach now much better. > > I still can't figure out the details between: > url("") > url(".") > url("/") > > while the first two seem to be equivalent, url("/") seems to link to > the > same url where the request() came from? No "/" - means default URL of the topmost application - root, the "." and "" refer to CURRENT application, i.e. the application that calls url() or render() that uses <% url ... %> If the path does not begin with "/" then relative URLs are sed. > e.g. when I request http://localhost:10000/gui/wrong_url > url("/") resolves to http://localhost:10000/gui/wrong_url > but url("") and url(".") resolves to > http://localhost:10000/gui > > When I use > dispatcher().assign("", &GUI::show_error_page, this); > mapper().assign("/"); // changed here instead of "" > See you are not consistent > dispatcher().assign("", &GUI::show_error_page, this); This would map show_error_page to some empty ending. > mapper().assign("/"); // changed here instead of "" Would create "/" as ending != "", In your case if the "show_error_page" is the default URL for the application then you should call mapper().assign(""); > the urls resolve to: > url("/") -> http://localhost:10000/gui/wrong_url > url(".") -> http://localhost:10000/gui/ > url("") -> http://localhost:10000/gui/ > Because "/" does not go to GUI but rather GUI's parent (topmost) > > Thanks, I think I do not need parameters, because I prefer to have > user/browser specific language and not by url. > Parameters rather define some named resource like /post/124 then the formatting would be "/post/{1}" and you would call url("post,124); >> Actually, wikipp was written before URL-mapper existed and I had >> no time to update it. Take a look rather on the cppcms's blog >> it uses url mapper fully. > > Ok, so I think the examples you gave in this mail are perfect! > Not sure so how to make it even more clear, because I assume more question will come. Artyom |