forked from artyom-beilis/cppcms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathurl_mapper.h
More file actions
380 lines (358 loc) · 12.7 KB
/
Copy pathurl_mapper.h
File metadata and controls
380 lines (358 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <[email protected]>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_URL_MAPPER_H
#define CPPCMS_URL_MAPPER_H
#include <cppcms/defs.h>
#include <cppcms/string_key.h>
#include <booster/noncopyable.h>
#include <booster/hold_ptr.h>
#include <cppcms/filters.h>
#include <string>
#include <vector>
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
/// <a href="<% url "/news/article" using article id %>" >...</a>
/// \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.
/// <br>
/// 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:
///
/// - <tt>assign("page","/wiki/{1}/page/{2}");</tt>
/// - <tt>assign("page","/wiki/{lang}/page/{1}");</tt>
/// - <tt>assign("page","/wiki/{lang}/page/main");</tt>
///
/// 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<string_key> &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<data> d;
};
};
#endif