/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #ifndef CPPCMS_URL_MAPPER_H #define CPPCMS_URL_MAPPER_H #include #include #include #include #include #include #include namespace cppcms { class application; /// /// \brief class for mapping URLs - the opposite of dispatch /// /// This class is useful for mapping between different page identifications /// that represent different classes/view and the URL. /// /// /// The URL mapping is done in hierarchy of applications where each application /// has its own name and they bundler into single hierarchy. Each application in hierarchy /// can be referred by its key and location. It may have different "urls" for mapping /// different values. /// /// For example, we develop a content management system with following tools: /// /// - site /// - news /// - article /// - category /// - forums /// - topics /// - threads /// - users /// - management /// - registration /// - profile /// /// Each node above is represented my cppcms::application and its children mounted /// to it. In order to access each URL we use "file system" like convention: /// /// - "/" - the default site page /// - "/news" - the default news page /// - "/news/article" - the default article page /// - "/news/category/by_date" - the categories pages sorted by data /// - "/news/category/by_interest" - the categories pages sorted by interest /// - "/news/category" - the default category pages /// /// And so on. /// /// Each application can be referred by its full path from root or by its relative path, /// so if we for example in article sub-application and we want to refer to "category" /// URL we would use something like map(out(),"../category/by_interest",category_id); /// /// In order to all this process work, each application should mount its children by some name, /// like: /// /// \code /// site::site(cppcms::service &s) : /// cppcms::application(s), /// news_(s), /// forums_(s), /// users_(s) /// { /// add(news_); /// mapper().mount("news","/news{1}",news_); /// add(forums_); /// mapper().mount("forums","/forums{1}",forums_); /// ... /// \endcode /// /// You can also use cppcms::application::add and cppcms::application::attach that allows /// to provide mapping for url_dispatcher and url_mapper in a single command like: /// /// \code /// add(news_, /// "news","/news{1}", /// "/news((/.*)?)",1); /// \endcode /// /// Which effectively the same as: /// /// \code /// add(news_); /// mapper().mount("news","/news{1}",news_); /// dispatcher().mount("/news((/.*)?)",news_,1); /// \endcode /// /// Such system allows using "url" tag in templates system easily as" /// /// \code /// " >... /// \endcode /// /// Each mounted application may a default URL (something like index.html) /// which is mapped when mounted application is referred. So for example there /// are may be following URLs: /// /// - "/news/article" or "/news/article/" - the default URL /// - "/news/article/preview" - preview unpublished article URL. /// /// They can be defined in article class as following: /// /// \code /// article::article(cppcms::service &s) : cppcms::application(s) /// { /// mapper().assign("/{1}"); // the default URL /// dispatcher().assign("/(\\d+)",&article::display,this,1); /// mapper().assign("preview","/{1}/preview"); // the preview URL /// dispatcher().assign("/(\\d+)/preview",&article::preview,this,1); /// } /// \endcode /// /// Additional supported feature is "named" parameters which are usually set to /// some default value using set_value, they are defined by special keywords between /// instead of numbers. /// /// For example assign("article", "/article/{lang}/{1}") were "lang" is special value for language /// defined by set_value("lang","en"), so mapping map(out(),"article",10) would create /// a URL "/article/en/10" /// /// Sometimes it is useful to change such values there are two ways to do it: /// /// - Overloading keyword with different parameters number assign("article","/article/{1}/{2}") /// and then calling map(out(),"article","ru",10) for URL like "/article/ru/10". /// - Using naming of parameters at mapping level by prepending comma separated keywords at the /// end of the path line after ";" map(out(),"article;lang","ru",10) - which would effectively work /// like temporary calling set_value("lang","ru") and then calling map(out(),"article",10). /// Unlike the previous case it also allows to do such changes globally. ///
/// For example if "news" application mounts article using "/{lang}/{1}" then /// using such mapping would affect top level URL that does not belong to specific application. /// /// /// /// /// /// class CPPCMS_API url_mapper : public booster::noncopyable { public: /// \cond INTERNAL url_mapper(application *app); ~url_mapper(); /// \endcond /// /// Get the root of the application - the string that /// is added to the any URL patter like "/forum" or /// "http://my.site.com" /// std::string root(); /// /// Set the root of the application - the string that /// is added to the any URL patter like "/forum" or /// "http://my.site.com" /// void root(std::string const &r); /// /// Provide a mapping between special \a key and a \a url pattern. /// /// URL patter is a string that includes mapped patters between "{" and "}" /// brackets. For example "/page/{1}" where "{1}" is being substituted /// by the first parameter in map functions. /// /// The ids can be numbers - 1 to 6 and special keys that can be changed /// in the run time using set_value functions. For example: /// /// "/wiki/{lang}/page/{1}" /// /// Where "lang" can be defined by "set_value". For example. /// /// For the url above with "lang" set to "en" and first parameter "cppcms" /// the string would be "/wiki/en/page/cppcms" /// /// Note the keys may be overloaded by number of parameters as for example: /// /// - assign("page","/wiki/{1}/page/{2}"); /// - assign("page","/wiki/{lang}/page/{1}"); /// - assign("page","/wiki/{lang}/page/main"); /// /// Then map(output,"page") - would create "/wiki/en/page/main", /// map(output,"page",134) would create "/wiki/en/page/132" and /// map(output,"page","ru","cppcms") would create "/wiki/ru/page/cppcms" /// /// Note: They keys containing "/", "," or ";" and keys with values "..", ".", "" are prohibited /// as they have special meanings /// void assign(std::string const &key,std::string const &url); /// /// Map the default key for the application, \a url has same rules as for assign(key,url) but /// they rather refer to default application's URL when it is used in hierarchy. /// void assign(std::string const &url); /// /// Set special value for a key that would be used /// in URL mapping, for example set_value("lang","en") /// /// Note: this value is defined globally for all applications hierarchy and not only /// for this specific application /// void set_value(std::string const &key,std::string const &value); /// /// Clear the special value - reset to empty /// /// Note: this value is cleared globally for all applications hierarchy and not only /// for this specific application /// void clear_value(std::string const &key); /// /// Write the URL to output stream \a out for the URL \a path with 0 parameters /// void map( std::ostream &out, char const *path); /// /// Write the URL to output stream \a out for the URL \a path with 1 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1); /// /// Write the URL to output stream \a out for the URL \a path with 2 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1, filters::streamable const &p2); /// /// Write the URL to output stream \a out for the URL \a path with 3 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3); /// /// Write the URL to output stream \a out for the URL \a path with 4 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4); /// /// Write the URL to output stream \a out for the URL \a path with 5 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4, filters::streamable const &p5); /// /// Write the URL to output stream \a out for the URL \a path with 6 parameters /// void map( std::ostream &out, char const *path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4, filters::streamable const &p5, filters::streamable const &p6); /// /// Write the URL to output stream \a out for the URL \a path with 0 parameters /// void map( std::ostream &out, std::string const &path); /// /// Write the URL to output stream \a out for the URL \a path with 1 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1); /// /// Write the URL to output stream \a out for the URL \a path with 2 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1, filters::streamable const &p2); /// /// Write the URL to output stream \a out for the URL \a path with 3 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3); /// /// Write the URL to output stream \a out for the URL \a path with 4 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4); /// /// Write the URL to output stream \a out for the URL \a path with 5 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4, filters::streamable const &p5); /// /// Write the URL to output stream \a out for the URL \a path with 6 parameters /// void map( std::ostream &out, std::string const &path, filters::streamable const &p1, filters::streamable const &p2, filters::streamable const &p3, filters::streamable const &p4, filters::streamable const &p5, filters::streamable const &p6); /// /// Mount sub application \a app using name \a name to \a url. /// /// The URL format as in assign but it requires a single parameter {1} /// which would be substituted with the mapping of the URL of sub-application /// instead of using "root" patch /// void mount(std::string const &name,std::string const &url,application &app); /// /// Get a mapper of mounted application by its name /// url_mapper &child(std::string const &name); /// /// Get a parent mapper, if not exists throws cppcms_error /// url_mapper &parent(); /// /// Get a topmost mapper, if have no parents returns reference to \c this. /// url_mapper &topmost(); private: void real_assign(std::string const &key,std::string const &url,application *child = 0); url_mapper &get_mapper_for_key(string_key const &key,string_key &real_key,std::vector &direct); url_mapper *root_mapper(); void real_map( char const *key, filters::streamable const *const *params, size_t params_no, std::ostream &output); struct data; booster::hold_ptr d; }; }; #endif