<!--toc--> |
|
## Conditions |
|
### Syntax |
|
Begin or continue conditional statement: |
|
( 'if' | 'elif' ) [ 'not' ] [ 'empty' ] ( VARIABLE | 'rtl' ) |
( 'if' | 'elif' ) '(' any-c++-expression ')' |
|
Else block: |
|
'else' |
|
Each if/else block should be ended with `end` statement. For example: |
|
<% if not empty username %> |
<h1>Hello <% username %></h1> |
<% else %> |
<h1>Hello Visitor</h1> |
<% end %> |
<% if ( content.n % 2==0 ) %> |
<% n %> is odd. |
<% elif ( content.n % 3 ==0) % > |
<% n %> can be divided by 3 without reminder. |
<% end %> |
|
### Description |
|
This is ordinary `if`/`else if` statement. You can specify following conditions: |
|
- By specifying variable or property you check whether it is true. |
- By specifying `empty` keyword you may check if specific STL container is empty by calling its member `empty()`. |
- You can negate the result using `not` |
- You can also check whether current locale referred to Right-To-Left language like Hebrew, Arabic or Persian by specifying `rtl` keyword. |
This condition actually checks in dictionary if string "LTR" is translated as "RTL". |
- You can specify arbitrary C++ conditional expression withing round brackets `()`. _Note_: Do not forget to refer to content variables using `content.` prefix. |
|
|
## Foreach block |
|
### Sytnax |
|
Major loop: |
|
'foreach' NAME ['as' IDENTIFIER ] [ 'rowid' IDENTIFIER [ 'from' NUMBER ] ] [ 'reverse' ] 'in' VARIABLE |
|
In case of empty collection: |
|
'empty' |
|
Specify central body: |
|
'item' |
'separator' |
|
For example: |
|
<% foreach student in students %> |
<ul> |
<% item %> |
<li><% student.id %>, <% student.name %></li> |
<% end %> |
</ul> |
<% empty %> |
<h2>No students</h2> |
<% end %> |
|
You can specify delimiter for elements between `separator` and `item` block: |
|
<% foreach student in students %> |
<% separator %>, <% item %><% student.name %><% end %> |
<% end %> |
|
Would generate a list like: "Ron, John, Moshe" |
|
### Description |
|
`foreach` loop creates a for loop that iterates any STL collection. The given name is a reference to |
the type returned by iterator. For example, if students is `std::list<student_t>` then `student` in above |
example is defined as `student_t &student`. |
|
- `reverse` - orders to use reverse iterator (rbegin,rend) |
- `rowid` - defines a special integer index that |
can be used for enumerating rows and optional `from` defines initial index value (default 0) |
|
For example |
|
<% foreach line rowid from 1 num in code %> |
<% foreach line rowid num from 1 in code %> |
<% item %><%= num %>:<%=line%><% end %> |
<% end %> |
|
_Note:_ `reverse` and `rowid` are supported starting from CppCMS 0.99.10 |
|
#### Type detection |
|
Template system uses one of following method for automatic type detection: |
|
1. C++0x `auto` |
2. C++0x `decltype` |
3. GCC's style `typeof` or `__typeof__` |
|
At least one of them should be supported by the compiler in order to provide correct template generation without |
using `as` keyword. |
|
But some compilers, most noticeable is MSVC8, MSVC9 still |
not support automatic type detection, thus, specific |
iterator type should be explicitly specified. |
|
For example: |
|
<% foreach student as students_type::iterator in students %> |
|
Would give you correct solution for MSVC compiler and `student` would a variable of type `students_type::iterator::value_type` |
|
#### Body |
|
`empty` statement is equivalent to "else" so: |
|
<% foreach a in b %> |
<ul> |
<% item %><% a %><% end %> |
</ul> |
<% empty %> |
nothing |
<% end %> |
|
Is generated into code like: |
|
if(!content.b.empty()) { |
out()<<"<ul>"; |
for(auto a_it=content.b.begin();a_it!=content.b.end();++a_it) { |
auto &a=*a_it; |
out()<<a; |
} |
out()<<"</ul>"; |
}else{ |
out()<<"nothing"; |
} |
|
You must provide `<% item %>...<% end %>` block for any `foreach` statement. |
If `separator` is used it should be added between `separator` and `item` blocks. |
|
### Custom form rendering |
|
CppCMS forms system provides several options for rendering form widgets, but sometimes custom rendering |
may be needed. In this case, `foreach` can be used to iterate over `cppcms::form` as over ordinary collation. |
|
For example, rendering with "new line" separator: |
|
<% foreach w in form %> |
<% separator %><br/><% item %> |
<% if w.has_message() %><% w.message() %>:<% end %> |
<% form input w %> |
<% if not w.valid() %>:<% w.error_message() %><% end %> |
<% end %> |
<% end %> |
|
## Caching Elements |
|
### Syntax |
|
The cached block begins with cache statement |
|
'cache' ( VARIABLE | STRING ) [ 'for' NUMBER ] ['on' 'miss' VARIABLE() ] [ 'no' 'triggers' ] [ 'no' 'recording' ] |
|
and ends with `end` statement. |
|
For example |
|
<% cache "sidebar" for 10 %> |
... |
<% end cache %> |
|
### Description |
|
This block allows to cache parts of rendered |
templates. The first parameter `( VARIABLE | STRING )` |
is mandatory and defines the key that is used to |
retrieve the frame from the cache. It should be |
either constant predefined string or some variable |
stored in the context. |
|
- `for NUMBER` - defines the number of seconds this block |
is stored. |
- `on miss VARIABLE()` defines the callback function that should be called if cache miss occurs. It allows for example |
to populate the context with some more data from the |
database. |
- `no triggers` - says that the cache key should not be added as trigger to the general cache. By default the key is added to the current triggers set, if `no triggers` defined it does not happen. |
|
For example: |
|
<% cache "foo" %> |
<% cache "bar" %> |
<% end %> |
<% end %> |
|
The `bar` trigger is added to `foo` and to all higher |
level object as dependent trigger. Thus calling |
`rise("bar")` would invalidate "foo" frame. |
|
However if you write: |
|
<% cache "foo" %> |
<% cache "bar" no triggers %> |
<% end %> |
<% end %> |
|
Then rising "bar" would not invalidate "foo". |
|
- `no recording` prevents from this object to record |
all triggers that where added during frame generation. |
|
For example: |
|
<% cache "foo" on miss load_data() %> |
... |
<% end %> |
|
void load_data(some_content &c) |
{ |
c.foo = .. // load some data from S |
cache().add_trigger("my_data"); |
} |
|
If `load_data()` is called it would add a trigger |
"my_data" to the cache and thus rising `my_data` |
would invalidate "foo". |
|
If `no recording` is provided |
|
<% cache "foo" on miss load_data() no recording %> |
|
Then the rising `my_data` would not invalidate |
"foo". |
|
|
## Adding Cache Triggers |
|
Strictly speaking this is not flow block but it |
is strongly connected to the `cache` block described |
above. |
|
trigger ( STRING | VARIABLE ) |
|
Says to add trigger to the current context effectively |
calling `cache().add_trigger(value)` |
|
|
For example: |
|
<% cache "foo" %> |
... |
<% trigger "bar" %> |
<% end cache %> |
|
Now rising `bar` as trigger would invalidate `foo` object. |
|
It is useful for some complex relations where you want |
to add triggers to cached frames explicitly. |