Fix switch. Update docs

This commit is contained in:
bzick 2014-05-14 17:07:48 +04:00
parent d8c4ea6994
commit c5f644c3db
9 changed files with 176 additions and 147 deletions

View File

@ -1,4 +1,8 @@
Adapters Adapters
======== ========
* [Fenom + Yii](https://bitbucket.org/RSol/rfenomviewrender) * [Fenom + Yii](https://bitbucket.org/RSol/rfenomviewrender)
* [Fenom + Kohana](https://github.com/2bj/kofenom) — Kofenom
* Fenom + Symphony
* Fenom + Symphony2
* Fenom + Zend Framework

94
docs/configuration.md Normal file
View File

@ -0,0 +1,94 @@
Setup
=====
## Configure
### Template cache
```php
$fenom->setCompileDir($dir);
```
This method set the name of the directory where template caches are stored. By default this is `/tmp`. This directory must be writeable.
### Template settings
```php
// set options using factory
$fenom = Fenom::factory($tpl_dir, $compile_dir, $options);
// or inline using method setOptions
$fenom->setOptions($options);
```
Options may by associative array like `'option_name' => true` or bitwise mask.
| Option name | Constant | Description | Affect |
| ---------------------- | ------------------------- | ------------ | ------- |
| *disable_methods* | `Fenom::DENY_METHODS` | disable calling methods of objects in templates. | |
| *disable_native_funcs* | `Fenom::DENY_NATIVE_FUNCS`| disable calling native function in templates, except allowed. | |
| *auto_reload* | `Fenom::AUTO_RELOAD` | reload template if source will be changed | decreases performance |
| *force_compile* | `Fenom::FORCE_COMPILE` | recompile template every time when the template renders | very decreases performance |
| *disable_cache* | `Fenom::DISABLE_CACHE` | disable compile cache | greatly decreases performance |
| *force_include* | `Fenom::FORCE_INCLUDE` | paste template body instead of include-tag | increases performance, increases cache size |
| *auto_escape* | `Fenom::AUTO_ESCAPE` | html-escape each variables outputs | decreases performance |
| *force_verify* | `Fenom::FORCE_VERIFY` | check existence every used variable | decreases performance |
| *auto_trim* | `Fenom::AUTO_TRIM` | remove space-characters before and after tags | |
| *disable_statics* | `Fenom::DENY_STATICS` | disable calling static methods in templates. | |
| *strip* | `Fenom::STRIP` | strip all whitespaces in templates. | decrease cache size |
```php
$fenom->setOptions(array(
"compile_check" => true,
"force_include" => true
));
// same
$fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_INCLUDE);
```
**Note**
By default all options disabled
## Extends
### Template providers [TRANSLATE]
Бывает так что шаблны не хранятся на файловой сиситеме, а хранятся в некотором хранилище, например, в базе данных MySQL.
В этом случае шаблонизатору нужно описать как забирать шаблоны из хранилища, как проверять дату изменения шаблона и где хранить кеш шаблонов (опционально).
Эту задачу берут на себя Providers, это объекты реальзующие интерфейс `Fenom\ProviderInterface`.
### Cache providers [TRANSLATE]
Изначально Fenom не расчитывался на то что кеш скомпиленых шаблонов может располагаться не на файловой системе.
Однако, в теории, есть возможность реализовать свое кеширование для скомпиленых шаблонов без переопределения шаблонизатора.
Речь идет о своем протоколе, отличным от `file://`, который [можно определить](http://php.net/manual/en/class.streamwrapper.php) в PHP.
Ваш протол должени иметь класс реализации протокола как указан в документации [Stream Wrapper](http://www.php.net/manual/en/class.streamwrapper.php).
Класс протокола может иметь не все указанные в документации методы. Вот список методов, необходимых шаблонизатору:
* [CacheStreamWrapper::stream_open](http://www.php.net/manual/en/streamwrapper.stream-open.php)
* [CacheStreamWrapper::stream_write](http://www.php.net/manual/en/streamwrapper.stream-write.php)
* [CacheStreamWrapper::stream_close](http://www.php.net/manual/en/streamwrapper.stream-close.php)
* [CacheStreamWrapper::rename](http://www.php.net/manual/en/streamwrapper.rename.php)
For `include`:
* [CacheStreamWrapper::stream_stat](http://www.php.net/manual/en/streamwrapper.stream-stat.php)
* [CacheStreamWrapper::stream_read](http://www.php.net/manual/en/streamwrapper.stream-read.php)
* [CacheStreamWrapper::stream_eof](http://www.php.net/manual/en/streamwrapper.stream-eof.php)
**Note**
2014-05-13 Zend OpCacher не поддерживает протоколы кроме `file://` и `phar://`.
For example,
```php
$this->setCacheDir("redis://hash/compiled/");
```
* `$cache = fopen("redis://hash/compiled/XnsbfeDnrd.php", "w");`
* `fwrite($cache, "... <template content> ...");`
* `fclose($cache);`
* `rename("redis://hash/compiled/XnsbfeDnrd.php", "redis://hash/compiled/main.php");`
### Callbacks and filters

View File

@ -1,19 +0,0 @@
Installation
============
For installation use [composer](http://getcomposer.org). Add in your `composer.json` requirements:
```json
{
"require": {
"fenom/fenom": "2.*"
}
}
```
or use shell
`composer require fenom/fenom`
If you do not use composer - use `psr-0` format for loading Fenom's classes or just register Fenom's autoloader:
```php
Fenom::registerAutoload();
```

View File

@ -1,14 +1,15 @@
Documentation Documentation
============= =============
**Please, help translate documentation to english or fix typos. [Read more](./helpme.md).**
### Fenom ### Fenom
* [Install](./install.md) * [Quick start](./start.md)
* [Usage](./usage.md) * [Usage](./start.md#install-fenom)
* [Fenom adapters](./adapters.md) * [Framework adapters](./adapters.md)
* [Develop](./dev/readme.md) * [For developers](./dev/readme.md)
* [Settings](./settings.md) * [Configuration](./settings.md)
* [Callbacks and filters](./callbacks.md)
* [Syntax](./syntax.md) * [Syntax](./syntax.md)
* [Operators](./operators.md) * [Operators](./operators.md)
@ -18,16 +19,16 @@ Documentation
[Usage](./syntax.md#modifiers) [Usage](./syntax.md#modifiers)
* [upper](./mods/upper.md) aka `up` * [upper](./mods/upper.md) aka `up` — convert to uppercase a string
* [lower](./mods/lower.md) aka `low` * [lower](./mods/lower.md) aka `low` — convert to lowercase a string
* [date_format](./mods/date_format.md) * [date_format](./mods/date_format.md) - format date, timestamp via strftime() function
* [date](./mods/date.md) * [date](./mods/date.md) - format date, timestamp via date() function
* [truncate](./mods/truncate.md) * [truncate](./mods/truncate.md) — truncate thee string to specified length
* [escape](./mods/escape.md) aka `e` * [escape](./mods/escape.md) aka `e` — escape the string
* [unescape](./mods/unescape.md) * [unescape](./mods/unescape.md) — unescape the string
* [strip](./mods/strip.md) * [strip](./mods/strip.md) — remove extra whitespaces
* [length](./mods/length.md) * [length](./mods/length.md) — calculate length of string, array, object
* [in](./mods/in.md) * [in](./mods/in.md) — find value in string or array
* allowed functions: `json_encode`, `json_decode`, `count`, `is_string`, `is_array`, `is_numeric`, `is_int`, `is_object`, * allowed functions: `json_encode`, `json_decode`, `count`, `is_string`, `is_array`, `is_numeric`, `is_int`, `is_object`,
`strtotime`, `gettype`, `is_double`, `ip2long`, `long2ip`, `strip_tags`, `nl2br` `strtotime`, `gettype`, `is_double`, `ip2long`, `long2ip`, `strip_tags`, `nl2br`
* or [add](./ext/mods.md) yours * or [add](./ext/mods.md) yours
@ -38,19 +39,19 @@ Documentation
[Usage](./syntax.md#tags) [Usage](./syntax.md#tags)
* [var](./tags/var.md) * [var](./tags/var.md) — define variable
* [if](./tags/if.md), `elseif` and `else` * [if](./tags/if.md), `elseif` and `else` — conditional statement
* [foreach](./tags/foreach.md), `foreaelse`, `break` and `continue` * [foreach](./tags/foreach.md), `foreaelse`, `break` and `continue` — traversing items in an array or object
* [for](./tags/for.md), `forelse`, `break` and `continue` * [for](./tags/for.md), `forelse`, `break` and `continue` — loop statement
* [switch](./tags/switch.md), `case`, `default` * [switch](./tags/switch.md), `case`, `default`
* [cycle](./tags/cycle.md) * [cycle](./tags/cycle.md) — cycles on an array of values
* [include](./tags/include.md), `insert` * [include](./tags/include.md), `insert` — includes and evaluates the specified template
* [extends](./tags/extends.md), `use`, `block` and `parent` * [extends](./tags/extends.md), `use`, `block` and `parent` — template inheritance
* [filter](./tags/filter.md) * [filter](./tags/filter.md) — apply modifier on a block of template data
* [ignore](./tags/ignore.md) * [ignore](./tags/ignore.md) — ignore Fenom syntax
* [macro](./tags/macro.md) and `import` * [macro](./tags/macro.md) and `import` — template functions
* [autoescape](./tags/autoescape.md) * [autoescape](./tags/autoescape.md) — escape template fragment
* [raw](./tags/raw.md) * [raw](./tags/raw.md) — unescape template fragment
* or [add](./ext/tags.md) yours * or [add](./ext/tags.md) yours
*** ***
@ -59,6 +60,5 @@ Documentation
* [Extensions](./ext/extensions.md) * [Extensions](./ext/extensions.md)
* [Add tags](./ext/tags.md) * [Add tags](./ext/tags.md)
* [Add modificators](./ext/mods.md) * [Add modifiers](./ext/mods.md)
* [Add template provider](./ext/provider.md)
* [Parsing](./ext/parsing.md) * [Parsing](./ext/parsing.md)

View File

@ -1,46 +0,0 @@
Settings
========
### Template cache
```php
$fenom->setCompileDir($dir);
```
This method set the name of the directory where template caches are stored. By default this is `/tmp`. This directory must be writeable.
### Template settings
```php
// set options using factory
$fenom = Fenom::factory($tpl_dir, $compile_dir, $options);
// or inline using method setOptions
$fenom->setOptions($options);
```
Options may by associative array like `'option_name' => true` or bitwise mask.
| Code | Constant | Description | Affect |
| ---------------------- | ------------------------- | ------------ | ------- |
| *disable_methods* | `Fenom::DENY_METHODS` | disable calling methods of objects in templates. | |
| *disable_native_funcs* | `Fenom::DENY_INLINE_FUNCS`| disable calling native function in templates, except allowed. | |
| *auto_reload* | `Fenom::AUTO_RELOAD` | reload template if source will be changed | decreases performance |
| *force_compile* | `Fenom::FORCE_COMPILE` | recompile template every time when the template renders | greatly decreases performance |
| *disable_cache* | `Fenom::DISABLE_CACHE` | disable compile cache | greatly decreases performance |
| *force_include* | `Fenom::FORCE_INCLUDE` | paste template body instead of include-tag | increases performance, increases cache size |
| *auto_escape* | `Fenom::AUTO_ESCAPE` | html-escape each variables outputs | decreases performance |
| *force_verify* | `Fenom::FORCE_VERIFY` | check existence every used variable | decreases performance |
| *auto_trim* | `Fenom::AUTO_TRIM` | remove space-characters before and after tags | |
| *disable_statics* | `Fenom::DENY_STATICS` | disable calling static methods in templates. | |
```php
$fenom->setOptions(array(
"compile_check" => true,
"force_include" => true
));
// same
$fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_INCLUDE);
```
**By default all options disabled**

View File

@ -5,7 +5,7 @@ Fenom implements [Smarty](http://www.smarty.net/) syntax with some improvements.
All Fenom tags enclosed in the delimiters `{` and `}`, for example `{var $five = 5}`. All Fenom tags enclosed in the delimiters `{` and `}`, for example `{var $five = 5}`.
If you wanna leave delimiters as is in the template use [special statements or tags](#ignoring-delimiters). If you wanna leave delimiters as is in the template use [special statements or tags](#ignoring-delimiters).
*Note* **Note**
Fenom implements [Smarty](http://www.smarty.net/) syntax but not implements Smarty tags, however, some tags very similar. Fenom implements [Smarty](http://www.smarty.net/) syntax but not implements Smarty tags, however, some tags very similar.
But not so bad, Fenom has the [extras](https://github.com/bzick/fenom-extra) that make Fenom like Smarty. But not so bad, Fenom has the [extras](https://github.com/bzick/fenom-extra) that make Fenom like Smarty.
@ -14,7 +14,7 @@ But not so bad, Fenom has the [extras](https://github.com/bzick/fenom-extra) tha
Variables in Fenom can be either displayed directly or used as arguments for functions, attributes and modifiers, Variables in Fenom can be either displayed directly or used as arguments for functions, attributes and modifiers,
inside conditional expressions, etc. inside conditional expressions, etc.
### Example variables ### Use variables
Next example uses simple variables `$user_id` ans `$user_name` Next example uses simple variables `$user_id` ans `$user_name`
```smarty ```smarty
@ -30,38 +30,37 @@ Example outputs next HTML code:
```smarty ```smarty
<div class="user">Hello, <a href="/users/{$user.id}">{$user.name}</a>.</div> <div class="user">Hello, <a href="/users/{$user.id}">{$user.name}</a>.</div>
``` ```
`{$user.id}` and `{$user['id']}` are same:
```smarty
<div class="user">Hello, <a href="/users/{$user['id']}">{$user.['name']}</a>.</div>
```
`{$user.id}` and `{$user['id']}` are same. В случае объекта, доступ к его свойствам осущесвляется так как и в PHP — через оператор `->`:
```smarty ```smarty
<div class="user">Hello, <a href="/users/{$user->id}">{$user->name}</a>.</div> <div class="user">Hello, <a href="/users/{$user->id}">{$user->name}</a>.</div>
``` ```
Методы, как и свойства можно вызвать через оператор `->`, передав в метод любые рагументы:
```smarty ```smarty
<div class="user">Hello, <a href="/users/{$user->getId()}">{$user->getName()}</a>.</div> <div class="user">Hello, <a href="/users/{$user->getId()}">{$user->getName()}</a>.</div>
``` ```
*Note* *Note*
Be careful, Fenom do not checks existence of the method before invoke. Be careful, Fenom do not checks existence of the method before invoke.
To avoid the problem class of the object have to define method `__call`, which throws an exception etc. To avoid the problem class of the object have to define method `__call`, which throws an exception, etc.
Also you may disable invoke method in [settings](./docs/settings.md). Also you can prohibit method call in [settings](./docs/configuration.md).
Multidimensional value support Можно комбинировать различные варианты вызовов:
```smarty ```smarty
{$foo.bar.baz} {$foo.bar.baz}
{$foo.$bar.$baz} {$foo.$bar.$baz}
{$foo[4].baz} {$foo[5].baz}
{$foo[4].$baz} {$foo[5].$baz}
{$foo.bar.baz[4]} {$foo.bar.baz[4]}
{$foo[ $bar.baz ]} {$foo[ $bar.baz ]}
``` {$foo[5]}
{$foo.5}
```smarty
{$foo}
{$bar}
{$foo[4]}
{$foo.4}
{$foo.bar} {$foo.bar}
{$foo.'bar'} {$foo.'bar'}
{$foo."bar"} {$foo."bar"}
@ -71,6 +70,8 @@ Multidimensional value support
{$foo[$bar]} {$foo[$bar]}
{$foo->bar} {$foo->bar}
{$foo->bar.buz} {$foo->bar.buz}
{$foo->bar.buz[ $bar->getId("user") ]}
{$foo->bar(5)->buz(5.5)}
``` ```
### System variable ### System variable
@ -107,16 +108,6 @@ Unnamed system variable starts with `$.` and allows access to global variables a
See all [operators](./operators.md) See all [operators](./operators.md)
### Object support
```smarty
{$object->item}
{$object->item|upper} {* apply modifier *}
{$object->item->method($y, 'named')}
{$object->item->method($y->name, 'named')|upper} {* apply modifier to method result*}
```
You may disable call methods in template, see in [security options](./settings.md) option `deny_method`
### Static method support ### Static method support
@ -196,7 +187,7 @@ but if use single quote any template expressions will be on display as it is
{'Hi, {$user.name|up}'} outputs "Hi, {$user.name|up}" {'Hi, {$user.name|up}'} outputs "Hi, {$user.name|up}"
``` ```
## Numbers ### Numbers
```smarty ```smarty
{2|pow:10} {2|pow:10}
@ -205,7 +196,7 @@ but if use single quote any template expressions will be on display as it is
{1e-6|round} {1e-6|round}
``` ```
### Modifiers ## Modifiers
* Modifiers allows change some value before output or using. * Modifiers allows change some value before output or using.
* To apply a modifier, specify the value followed by a `|` (pipe) and the modifier name. * To apply a modifier, specify the value followed by a `|` (pipe) and the modifier name.
@ -224,7 +215,7 @@ but if use single quote any template expressions will be on display as it is
[List of modifiers](./main.md#modifiers) [List of modifiers](./main.md#modifiers)
### Tags ## Tags
Basically, tag seems like Basically, tag seems like
@ -273,12 +264,13 @@ Tags starts with name and may have attributes
### Ignoring template code ### Ignoring template code
В шаблонизаторе Fenom используются фигурные скобки для отделения HTML от кода Fenom. В шаблонизаторе Fenom используются фигурные скобки для отделения HTML от кода Fenom.
Если требуется вывести текст, содержащий фигурные скобки, помните о следующих возможностях: Если требуется вывести текст, содержащий фигурные скобки, то есть следующие варианты это сделать:
1. Использование блочного тега `{ignore}{/ignore}`. Текст внутри этого тега текст не компилируется шаблонизатором и выводится как есть. 1. Использование блочного тега `{ignore}{/ignore}`. Текст внутри этого тега текст не компилируется шаблонизатором и выводится как есть.
2. Если после открывающей фигурной скобки есть пробельный символ (пробел или `\t`) или перенос строки (`\r` или `\n`), то она не воспринимается как разделитель кода Fenom и код после неё выводится как есть. 2. Если после открывающей фигурной скобки есть пробельный символ (пробел или `\t`) или перенос строки (`\r` или `\n`), то она не воспринимается как разделитель кода Fenom и код после неё выводится как есть.
3. Установить опцию `:ignore` у блочного тега. Все Fenom теги внутри блока будут проигнорированны
Пример: Example:
```smarty ```smarty
{ignore} {ignore}
@ -292,10 +284,10 @@ Tags starts with name and may have attributes
e.innerHTML = text; e.innerHTML = text;
document.body.appendChild(e); document.body.appendChild(e);
})('test'); })('test');
</script> {if:ignore $cdn.yandex}
{if:ignore $js_enabled} var item = {cdn: "//yandex.st/"};
{/if} {/if}
</script>
``` ```
Outputs Outputs
@ -310,6 +302,7 @@ Outputs
e.innerHTML = text; e.innerHTML = text;
document.body.appendChild(e); document.body.appendChild(e);
})('test'); })('test');
var item = {cdn: "//yandex.st/"};
</script> </script>
``` ```
@ -341,10 +334,7 @@ Outputs
| name | code | type | description | | name | code | type | description |
| ------- | ---- | ----- | ------------ | | ------- | ---- | ----- | ------------ |
| strip | s | block | remove any multi-whitespaces | | strip | s | block | enable `strip` option for a block of the template |
| ltrim | l | any | remove spaces left of the tag |
| rtrim | r | any | remove spaces right of the tag |
| trim | t | any | remove spaces near tag |
| raw | a | any | ignore escape option | | raw | a | any | ignore escape option |
| escape | e | any | force escape | | escape | e | any | force escape |
| ignore | i | block | ignore Fenom syntax | | ignore | i | block | ignore Fenom syntax |

View File

@ -15,7 +15,7 @@ Tag `{switch}` accepts any expression. But `{case}` accepts only static scalar v
... ...
{case <value3>} {case <value3>}
... ...
{default case <value1>} {case default, <value1>}
... ...
{/switch} {/switch}
``` ```
@ -32,7 +32,7 @@ For example,
It is current item It is current item
{case 'new', 'newer'} {case 'new', 'newer'}
It is new item, again It is new item, again
{default} {case default}
I don't know the type {$type} I don't know the type {$type}
{/switch} {/switch}
``` ```

View File

@ -366,10 +366,10 @@ class Compiler
private static function _caseResort(Tag $scope) private static function _caseResort(Tag $scope)
{ {
$content = $scope->cutContent(); $content = $scope->cutContent();
if ($scope["last"] === false) { foreach ($scope["last"] as $case) {
$scope["default"] .= $content; if($case === false) {
} else { $scope["default"] .= $content;
foreach ($scope["last"] as $case) { } else {
if (!isset($scope["case"][$case])) { if (!isset($scope["case"][$case])) {
$scope["case"][$case] = ""; $scope["case"][$case] = "";
} }
@ -384,14 +384,19 @@ class Compiler
* *
* @static * @static
* @param Tokenizer $tokens * @param Tokenizer $tokens
* @param Tag $scope * @param Tag $tag
* @return string * @return string
*/ */
public static function tagCase(Tokenizer $tokens, Tag $scope) public static function tagCase(Tokenizer $tokens, Tag $tag)
{ {
self::_caseResort($scope); self::_caseResort($tag);
do { do {
$scope["last"][] = $scope->tpl->parseScalar($tokens, false); if($tokens->is(T_DEFAULT)) {
$tag["last"][] = false;
$tokens->next();
} else {
$tag["last"][] = $tag->tpl->parseScalar($tokens, false);
}
if ($tokens->is(',')) { if ($tokens->is(',')) {
$tokens->next(); $tokens->next();
} else { } else {
@ -413,7 +418,7 @@ class Compiler
public static function tagDefault($tokens, Tag $scope) public static function tagDefault($tokens, Tag $scope)
{ {
self::_caseResort($scope); self::_caseResort($scope);
$scope["last"] = false; $scope["last"][] = false;
return ''; return '';
} }

View File

@ -861,7 +861,7 @@ class TemplateTest extends TestCase
$code1 = 'Switch: {switch $a} $code1 = 'Switch: {switch $a}
{case 1, "one"} one {case 1, "one"} one
{case 2, "two"} two {case 2, "two"} two
{case "string"} str {case "string", default} str
{default} def {default} def
{/switch} end'; {/switch} end';
@ -881,6 +881,7 @@ class TemplateTest extends TestCase
array($code1, array("a" => 2), 'Switch: two end'), array($code1, array("a" => 2), 'Switch: two end'),
array($code1, array("a" => 'two'), 'Switch: two end'), array($code1, array("a" => 'two'), 'Switch: two end'),
array($code1, array("a" => "string"), 'Switch: str end'), array($code1, array("a" => "string"), 'Switch: str end'),
array($code1, array("a" => "unk"), 'Switch: str def end'),
array($code2, array("a" => "unk"), 'Switch: end'), array($code2, array("a" => "unk"), 'Switch: end'),
array($code3, array("a" => 1), 'Switch: one end'), array($code3, array("a" => 1), 'Switch: one end'),
array($code3, array("a" => 'one'), 'Switch: one end'), array($code3, array("a" => 'one'), 'Switch: one end'),