diff --git a/bin/cppcms_tmpl_cc b/bin/cppcms_tmpl_cc index ab34c5f..3a55fce 100755 --- a/bin/cppcms_tmpl_cc +++ b/bin/cppcms_tmpl_cc @@ -553,9 +553,9 @@ class url_block: if m.group(3): params=make_format_params(m.group(4),'urlencode') if not params: - output( "out()< #include #include +#include #endif diff --git a/examples/message_board/apps/forums.cpp b/examples/message_board/apps/forums.cpp index cd8b49a..e85edec 100644 --- a/examples/message_board/apps/forums.cpp +++ b/examples/message_board/apps/forums.cpp @@ -26,6 +26,9 @@ namespace apps { forums::forums(cppcms::service &srv) : master(srv) { + mapper().assign("{1}"); // with id + mapper().assign(""); // default + dispatcher().assign(".*",&forums::prepare,this,0); } void forums::prepare_content(data::forums &c,std::string const &page) diff --git a/examples/message_board/apps/mb.cpp b/examples/message_board/apps/mb.cpp index 598d4b9..9c7f1e5 100644 --- a/examples/message_board/apps/mb.cpp +++ b/examples/message_board/apps/mb.cpp @@ -10,39 +10,33 @@ namespace apps { -mb::mb(cppcms::service &s) : - cppcms::application(s) +mb::mb(cppcms::service &s) : cppcms::application(s) { - mapper().root(settings().get("mb.root")); - // Forums - forums *forums_ptr = new forums(s); - attach(forums_ptr); - dispatcher().assign("(/(\\d+)?)?",&forums::prepare,forums_ptr,2); - mapper().assign("forums","/"); - mapper().assign("forums","/{1}"); - - - // Flat thread - flat_thread *flat_ptr = new flat_thread(s); - attach(flat_ptr); - dispatcher().assign("/flat/(\\d+)",&flat_thread::prepare,flat_ptr,1); - mapper().assign("flat_thread","/flat/{1}"); - - // Tree thread - tree_thread *tree_ptr = new tree_thread(s); - attach(tree_ptr); - dispatcher().assign("/tree/(\\d+)",&tree_thread::prepare,tree_ptr,1); - mapper().assign("tree_thread","/tree/{1}"); + attach( new forums(s), + "forums", + "/{1}", + "(/(\\d+)?)?",2); + + attach( new flat_thread(s), + "flat_thread", + "/flat/{1}", + "/flat/(\\d+)",1); + + + attach( new tree_thread(s), + "tree_thread", + "/tree/{1}", + "/tree/(\\d+)",1); + + attach( new reply(s), + "comment", + "/comment/{1}", + "/comment/(\\d+)",1); // Generic mapping + mapper().root(settings().get("mb.root")); mapper().assign("user_thread","/{method}/{1}"); - - // Reply - reply *repl_ptr = new reply(s); - attach(repl_ptr); - dispatcher().assign("/comment/(\\d+)",&reply::prepare,repl_ptr,1); - mapper().assign("comment","/comment/{1}"); } } // apps diff --git a/examples/message_board/apps/mb.h b/examples/message_board/apps/mb.h index f82b7b4..e677f06 100644 --- a/examples/message_board/apps/mb.h +++ b/examples/message_board/apps/mb.h @@ -3,11 +3,11 @@ #include - namespace apps { class mb : public cppcms::application { public: + mb(cppcms::service &s); }; diff --git a/examples/message_board/apps/thread.cpp b/examples/message_board/apps/thread.cpp index c9483ea..d3cdfea 100644 --- a/examples/message_board/apps/thread.cpp +++ b/examples/message_board/apps/thread.cpp @@ -68,7 +68,8 @@ bool thread_shared::prepare(data::thread_shared &c,int id) flat_thread::flat_thread(cppcms::service &s) : thread_shared(s) { - + dispatcher().assign(".*",&flat_thread::prepare,this,0); + mapper().assign("{1}"); } @@ -125,6 +126,8 @@ void make_tree(data::tree_t &messages,std::map > &co tree_thread::tree_thread(cppcms::service &s) : thread_shared(s) { + dispatcher().assign(".*",&tree_thread::prepare,this,0); + mapper().assign("{1}"); } @@ -166,6 +169,8 @@ void tree_thread::prepare(std::string sid) reply::reply(cppcms::service &srv) : thread_shared(srv) { + dispatcher().assign(".*",&reply::prepare,this,0); + mapper().assign("{1}"); } void reply::prepare(std::string smid) diff --git a/examples/message_board/view/forums.tmpl b/examples/message_board/view/forums.tmpl index 9666278..0d380e2 100644 --- a/examples/message_board/view/forums.tmpl +++ b/examples/message_board/view/forums.tmpl @@ -11,7 +11,7 @@

<% gt "No Topics" %>

<% end %>

<% gt "Create New Disussion" %>

-
+ " method="post" > <% form as_p form %>
<% end template %> diff --git a/src/application.cpp b/src/application.cpp index bd16d97..e472af8 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -166,11 +166,26 @@ void application::add(application &app) if(app.parent()!=this) app.parent(this); } -void application::add(application &app,std::string regex,int part) +void application::add(application &app,std::string const ®ex,int part) { add(app); dispatcher().mount(regex,app,part); } + +void application::add(application &app,std::string const &name,std::string const &url) +{ + add(app); + mapper().mount(name,url,app); +} + +void application::add(application &app,std::string const &name,std::string const &url,std::string const ®ex,int part) +{ + add(app); + dispatcher().mount(regex,app,part); + mapper().mount(name,url,app); +} + + void application::attach(application *app) { d->managed_children.push_back(app); @@ -208,10 +223,21 @@ void application::main(std::string url) } } -void application::attach(application *app,std::string regex,int part) +void application::attach(application *app,std::string const ®ex,int part) { - d->managed_children.push_back(app); - add(*app,regex,part); + attach(app); + dispatcher().mount(regex,*app,part); +} +void application::attach(application *app,std::string const &name,std::string const &url) +{ + attach(app); + mapper().mount(name,url,*app); +} +void application::attach(application *app,std::string const &name,std::string const &url,std::string const ®ex,int part) +{ + attach(app); + dispatcher().mount(regex,*app,part); + mapper().mount(name,url,*app); } void application::render(std::string template_name,base_content &content) @@ -226,29 +252,6 @@ void application::render(std::string skin,std::string template_name,base_content service().views_pool().render(skin,template_name,response().out(),content); } -void application::render(std::string template_name) -{ - base_content *cnt = dynamic_cast(this); - if(!cnt) { - throw cppcms_error( "Can't use application::render(std::string) when the application " - "is not derived from base_content"); - } - render(template_name,*cnt); -} - -void application::render(std::string skin,std::string template_name) -{ - base_content *cnt = dynamic_cast(this); - if(!cnt) { - throw cppcms_error( "Can't use application::render(std::string,std::string) when the application " - "is not derived from base_content"); - } - render(skin,template_name,*cnt); -} - - - - void application::render(std::string template_name,std::ostream &out,base_content &content) { rnd_guard g(content,this); diff --git a/src/url_mapper.cpp b/src/url_mapper.cpp index d29b751..da366b4 100644 --- a/src/url_mapper.cpp +++ b/src/url_mapper.cpp @@ -24,6 +24,8 @@ #include +#include + namespace cppcms { struct url_mapper::data { @@ -52,12 +54,25 @@ namespace cppcms { { by_key_type::const_iterator kp = by_key.find(key); if(kp == by_key.end()) - throw cppcms_error("url_mapper: key " + key + " not found"); + throw cppcms_error("url_mapper: key `" + key + "' not found"); by_size_type::const_iterator sp = kp->second.find(params_no); if(sp == kp->second.end()) throw cppcms_error("url_mapper: invalid number of parameters for " + key); return sp->second; } + + url_mapper *is_app(std::string const &key) const + { + by_key_type::const_iterator kp = by_key.find(key); + if(kp == by_key.end()) + return 0; + by_size_type::const_iterator sp = kp->second.begin(); + if(sp==kp->second.end()) + return 0; + if(sp->second.child) + return &sp->second.child->mapper(); + return 0; + } url_mapper &child(std::string const &name) { @@ -109,8 +124,12 @@ namespace cppcms { } } + if(parent) { - parent->mapper().map(output,this_name,ss.str()); + std::string url = ss.str(); + filters::streamable stream_url(url); + filters::streamable const *par_ptr=&stream_url; + parent->mapper().d->map(this_name,&par_ptr,1,data_helpers,output); } } @@ -119,10 +138,6 @@ namespace cppcms { void url_mapper::assign(std::string const &key,std::string const &url) { - real_assign(key,url,0); - } - void url_mapper::real_assign(std::string const &key,std::string const &url,application *child) - { if( key.empty() || key.find('/') != std::string::npos || key ==".." @@ -130,6 +145,14 @@ namespace cppcms { { throw cppcms_error("cppcms::url_mapper: key may not be '' , '.' or '..' and must not include '/' in it"); } + real_assign(key,url,0); + } + void url_mapper::assign(std::string const &url) + { + real_assign(std::string(),url,0); + } + void url_mapper::real_assign(std::string const &key,std::string const &url,application *child) + { data::entry e; std::string::const_iterator prev = url.begin(), p = url.begin(); @@ -183,7 +206,25 @@ namespace cppcms { throw cppcms_error("cppcms::url_mapper the application mapping should use only 1 parameter"); } e.parts.push_back(std::string(prev,p)); + e.child = child; + + if(child) { + if(d->by_key.find(key)!=d->by_key.end()) + throw cppcms_error( "cppcms::url_mapper: mounted application key `" + key + + "' can't be shared with ordinary url key"); + } + else { + data::by_key_type::iterator p = d->by_key.find(key); + if(p!=d->by_key.end()) { + data::by_size_type::const_iterator p2 = p->second.find(1); + if(p2!=p->second.end() && p2->second.child) + { + throw cppcms_error( "cppcms::url_mapper: ordinary url key `"+key+ + "can't be shared with mounted application key"); + } + } + } d->by_key[key][max_index] = e; } @@ -258,6 +299,12 @@ namespace cppcms { size_t end = key.find('/',pos); if(end == std::string::npos) { real_key = key.substr(pos); + url_mapper *tmp = mapper->d->is_app(real_key); + if(tmp) { + // empty special key + real_key.clear(); + return *tmp; + } return *mapper; } size_t chunk_size = end - pos; diff --git a/tests/url_mapper_test.cpp b/tests/url_mapper_test.cpp index 08023be..5fbfcf9 100644 --- a/tests/url_mapper_test.cpp +++ b/tests/url_mapper_test.cpp @@ -125,7 +125,8 @@ void basic_test() struct test1 : public cppcms::application { test1(cppcms::service &s) : cppcms::application(s) { - mapper().assign("default","/"); + mapper().assign("/default"); + mapper().assign("somepath","/"); mapper().assign("page","/{1}"); mapper().assign("preview","/{1}/preview"); mapper().assign("bylang","/{lang}"); @@ -138,7 +139,7 @@ struct test2 : public cppcms::application { cppcms::application(s), bee(s) { - mapper().assign("default","/"); + mapper().assign("somepath","/"); mapper().assign("page","/{1}"); mapper().assign("preview","/{1}/preview"); mapper().mount("bee","/bee{1}",bee); @@ -161,7 +162,7 @@ struct test_app : public cppcms::application { mapper().mount("foo","/foo{1}",foo); mapper().mount("bar","/bar{1}",bar); mapper().mount("foobar","/foobar{1}",bee); - mapper().assign("default","/test"); + mapper().assign("somepath","/test"); mapper().root("xx"); bee.bee.mapper().set_value("lang","en"); @@ -169,31 +170,32 @@ struct test_app : public cppcms::application { void test_hierarchy() { std::ostringstream ss; - mapper().map(ss,"default"); + mapper().map(ss,"somepath"); TEST(value(ss) == "xx/test"); - foo.mapper().map(ss,"default"); + foo.mapper().map(ss,"somepath"); TEST(value(ss) == "xx/foo/"); foo.mapper().map(ss,"page",1); TEST(value(ss) == "xx/foo/1"); foo.mapper().map(ss,"preview",1); TEST(value(ss) == "xx/foo/1/preview"); - bar.mapper().map(ss,"default"); + bar.mapper().map(ss,"somepath"); TEST(value(ss) == "xx/bar/"); bar.mapper().map(ss,"page",1); TEST(value(ss) == "xx/bar/1"); bar.mapper().map(ss,"preview",1); TEST(value(ss) == "xx/bar/1/preview"); - bee.mapper().map(ss,"default"); + + bee.mapper().map(ss,"somepath"); TEST(value(ss) == "xx/foobar/"); bee.mapper().map(ss,"page",1); TEST(value(ss) == "xx/foobar/1"); bee.mapper().map(ss,"preview",1); TEST(value(ss) == "xx/foobar/1/preview"); - bee.bee.mapper().map(ss,"default"); + bee.bee.mapper().map(ss,"somepath"); TEST(value(ss) == "xx/foobar/bee/"); bee.bee.mapper().map(ss,"page",1); TEST(value(ss) == "xx/foobar/bee/1"); @@ -212,31 +214,36 @@ struct test_app : public cppcms::application { } void test_mapping() { - TEST(u(*this,"/default")=="xx/test"); - TEST(u(*this,"/foo/default")=="xx/foo/"); - TEST(u(*this,"/foobar/bee/default")=="xx/foobar/bee/"); + TEST(u(*this,"/somepath")=="xx/test"); + TEST(u(*this,"/foo/somepath")=="xx/foo/"); + TEST(u(*this,"/foo/")=="xx/foo/default"); + TEST(u(*this,"/foo")=="xx/foo/default"); + TEST(u(*this,"/foobar/bee/")=="xx/foobar/bee/default"); + TEST(u(*this,"/foobar/bee")=="xx/foobar/bee/default"); TEST(u(*this,"/foobar/bee/bylang")=="xx/foobar/bee/en"); - TEST(u(*this,"default")=="xx/test"); - TEST(u(*this,"foo/default")=="xx/foo/"); - TEST(u(*this,"foobar/bee/default")=="xx/foobar/bee/"); + TEST(u(*this,"somepath")=="xx/test"); + TEST(u(*this,"foo/somepath")=="xx/foo/"); + TEST(u(*this,"foobar/bee/somepath")=="xx/foobar/bee/"); TEST(u(*this,"foobar/bee/bylang")=="xx/foobar/bee/en"); - TEST(u(bar,"/default")=="xx/test"); - TEST(u(bar,"/foo/default")=="xx/foo/"); - TEST(u(bar,"/foobar/bee/default")=="xx/foobar/bee/"); + TEST(u(bar,"/somepath")=="xx/test"); + TEST(u(bar,"/foo/somepath")=="xx/foo/"); + TEST(u(bar,"/foobar/bee/somepath")=="xx/foobar/bee/"); + TEST(u(bar,"/foobar/bee/")=="xx/foobar/bee/default"); + TEST(u(bar,"/foobar/bee")=="xx/foobar/bee/default"); TEST(u(bar,"/foobar/bee/bylang")=="xx/foobar/bee/en"); - TEST(u(bee.bee,"/default")=="xx/test"); - TEST(u(bee.bee,"/foo/default")=="xx/foo/"); - TEST(u(bee.bee,"/foobar/bee/default")=="xx/foobar/bee/"); + TEST(u(bee.bee,"/somepath")=="xx/test"); + TEST(u(bee.bee,"/foo/somepath")=="xx/foo/"); + TEST(u(bee.bee,"/foobar/bee/somepath")=="xx/foobar/bee/"); TEST(u(bee.bee,"/foobar/bee/bylang")=="xx/foobar/bee/en"); - TEST(u(bee.bee,"default")=="xx/foobar/bee/"); + TEST(u(bee.bee,"somepath")=="xx/foobar/bee/"); TEST(u(bee.bee,"bylang")=="xx/foobar/bee/en"); - TEST(u(bee.bee,"../default")=="xx/foobar/"); - TEST(u(bee.bee,"../../default")=="xx/test"); + TEST(u(bee.bee,"../somepath")=="xx/foobar/"); + TEST(u(bee.bee,"../../somepath")=="xx/test"); TEST(u(bee.bee,"bylang")=="xx/foobar/bee/en"); TEST(u(foo,"../foobar/bee/bylang")=="xx/foobar/bee/en"); }