mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
commit
48f42c82a9
80
README.md
80
README.md
@ -1,31 +1,69 @@
|
|||||||
Fenom - Template Engine for PHP
|
Fenom - Template Engine for PHP
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
> Composer [package](https://packagist.org/packages/fenom/fenom): `{"fenom/fenom": "2.*"}`. <br />
|
**Fenóm** - lightweight and fast template engine for PHP.
|
||||||
> For old version: `{"fenom/fenom": "1.*"}`. <br />
|
|
||||||
> [List](https://github.com/fenom-template/fenom/wiki/Migrate-from-1.4.9-to-2.0) of incompatibilities between **1** and **2** versions.
|
|
||||||
|
|
||||||
[](https://packagist.org/packages/fenom/fenom)
|
* **Subject:** Template engine
|
||||||
[](https://travis-ci.org/fenom-template/fenom)
|
* **Syntax:** Smarty-like
|
||||||
[](https://coveralls.io/r/fenom-template/fenom?branch=master)
|
* **Documentation:** **[English](./docs/en/readme.md)**, **[Russian](./docs/ru/readme.md)**
|
||||||
[](https://packagist.org/packages/fenom/fenom)
|
* **PHP version:** 5.3+
|
||||||
|
* **State:** [](https://travis-ci.org/fenom-template/fenom) [](https://coveralls.io/r/fenom-template/fenom?branch=master)
|
||||||
|
* **Version:** [](https://packagist.org/packages/fenom/fenom)
|
||||||
|
* **Packagist:** [fenom/fenom](https://packagist.org/packages/fenom/fenom) [](https://packagist.org/packages/fenom/fenom)
|
||||||
|
* **Composer:** `composer require fenom/fenom`
|
||||||
|
* **Discussion:** [Fenom Forum](https://groups.google.com/forum/#!forum/php-ion)
|
||||||
|
* **Versioning:** [semver2](http://semver.org/)
|
||||||
|
* **Performance:** see [benchmark](./docs/en/benchmark.md)
|
||||||
|
|
||||||
## [Quick start](./docs/en/start.md) :: [Documentation](./docs/readme.md) [[en](./docs/en/readme.md)|[ru](./docs/ru/readme.md)] :: [Benchmark](./docs/en/benchmark.md)
|
***
|
||||||
<!-- :: [Articles](./docs/articles.md) -->
|
|
||||||
|
|
||||||
### What is it
|
## Quick Start
|
||||||
|
|
||||||
**Fenóm** — lightweight template engine for PHP.
|
### Install
|
||||||
|
|
||||||
It means:
|
If you use composer in your project then you can to install Fenom as package.
|
||||||
|
However, if you are not using composer you have to configure _autoloader_ to work with Fenom.
|
||||||
|
Fenom implements the `PSR-0` PHP standard to load classes which are located in the `src/` directory.
|
||||||
|
Templater already has own autoload-function, to register call method `Fenom::registerAutoload`:
|
||||||
|
```php
|
||||||
|
Fenom::registerAutoload();
|
||||||
|
```
|
||||||
|
|
||||||
* Known Smarty-like [syntax](./docs/en/syntax.md) with improvements.
|
### Setup
|
||||||
* Very [fast](./docs/en/benchmark.md).
|
|
||||||
* [Lightweight](./docs/en/benchmark.md).
|
|
||||||
* Very [flexible](./docs/en/configuration.md#extends).
|
|
||||||
* Progressive parser without regular expressions.
|
|
||||||
* High [code coverage](https://coveralls.io/r/bzick/fenom?branch=master).
|
|
||||||
* Easy to understand [how it works](./docs/en/dev/readme.md).
|
|
||||||
* Easy to [use](./docs/en/start.md).
|
|
||||||
* Maximum [protection](./docs/en/configuration.md#configure).
|
|
||||||
|
|
||||||
|
There is two way to create Fenom instance:
|
||||||
|
|
||||||
|
* Long way: use operator `new`
|
||||||
|
* Shot way: use static factory-method
|
||||||
|
|
||||||
|
**Long way.** Create you own template provider or default provider `Fenom\Provider` (that is provider read [there](./)).
|
||||||
|
Using provider instance create Fenom instance:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fenom = new Fenom(new Fenom\Provider($template_dir));
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, set compile directory:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fenom->setCompileDir($template_cache_dir);
|
||||||
|
```
|
||||||
|
|
||||||
|
This directory will be used for storing compiled templates, therefore it should be writable for Fenom.
|
||||||
|
Now Fenom is ready to work and now you can to configure it:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fenom->setOptions($options);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Short way.** Creating an object via factory method with arguments from long way.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$fenom = Fenom::factory($template_dir, $template_cache_dir, $options);
|
||||||
|
```
|
||||||
|
|
||||||
|
Now Fenom is ready to work.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
### Example
|
@ -55,7 +55,7 @@ Operators
|
|||||||
{if $a & 1} {var $b = 4 | $flags} {/if}
|
{if $a & 1} {var $b = 4 | $flags} {/if}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Assignment Operators
|
### Assignment operators
|
||||||
|
|
||||||
* `$a = $b` - assignment
|
* `$a = $b` - assignment
|
||||||
* `$a += $b` - assignment with addition
|
* `$a += $b` - assignment with addition
|
||||||
@ -81,9 +81,11 @@ Operators
|
|||||||
* `--$a` - decrement the variable and use it
|
* `--$a` - decrement the variable and use it
|
||||||
* `$a--` - use the variable and decrement it
|
* `$a--` - use the variable and decrement it
|
||||||
|
|
||||||
### String operator
|
### String operators
|
||||||
|
|
||||||
* `$a ~ $b` - return concatenation of variables `$a` and `$b`
|
* `$a ~ $b` - return concatenation of variables `$a` and `$b`
|
||||||
|
* `$a ~~ $b` - return concatenation of variables `$a` and `$b` separated by a space
|
||||||
|
* `$a ~= $b` - assignment with concatenation
|
||||||
|
|
||||||
### Ternary operators
|
### Ternary operators
|
||||||
|
|
||||||
|
@ -23,22 +23,26 @@ Documentation
|
|||||||
|
|
||||||
[Usage](./syntax.md#tags)
|
[Usage](./syntax.md#tags)
|
||||||
|
|
||||||
* [set](./tags/var.md), `add` and `var` — define variables
|
* [set](./tags/set.md), [add](./tags/set.md#add) and `var` — define variables
|
||||||
* [if](./tags/if.md), `elseif` and `else` — conditional statement
|
* [if](./tags/if.md), [elseif](./tags/if.md#elseif) and [else](./tags/if.md#else) — conditional statement
|
||||||
* [foreach](./tags/foreach.md), `foreaelse`, `break` and `continue` — traversing items in an array or object
|
* [foreach](./tags/foreach.md), [foreaelse](./tags/foreach.md#foreaelse),
|
||||||
* [for](./tags/for.md), `forelse`, `break` and `continue` — loop statement
|
[break](./tags/foreach.md#break) and [continue](./tags/foreach.md#continue) — traversing items in an array or object
|
||||||
* [switch](./tags/switch.md), `case`, `default` —
|
* [switch](./tags/switch.md), [case](./tags/switch.md#case) — complex condition statement
|
||||||
* [cycle](./tags/cycle.md) — cycles on an array of values
|
* [cycle](./tags/cycle.md) — cycles on an array of values
|
||||||
* [include](./tags/include.md), `insert` — includes and evaluates the specified template
|
* [include](./tags/include.md), [insert](./tags/include.md#insert) — includes and evaluates the specified template
|
||||||
* [extends](./tags/extends.md), `use`, `block` and `parent` — template inheritance
|
* [extends](./tags/extends.md), [use](./tags/extends.md#use),
|
||||||
|
[block](./tags/extends.md#block), [parent](./tags/extends.md#parent) and [paste](./tags/extends.md#paste) — template inheritance
|
||||||
* [filter](./tags/filter.md) — apply modifier on a block of template data
|
* [filter](./tags/filter.md) — apply modifier on a block of template data
|
||||||
* [ignore](./tags/ignore.md) — ignore Fenom syntax
|
* [ignore](./tags/ignore.md) — ignore Fenom syntax
|
||||||
* [macro](./tags/macro.md) and `import` — template functions
|
* [macro](./tags/macro.md) and [import](./tags/macro.md#import) — template functions
|
||||||
* [autoescape](./tags/autoescape.md) — escape template fragment
|
* [autoescape](./tags/autoescape.md) — escape template fragment
|
||||||
* [raw](./tags/raw.md) — unescape template fragment
|
* [raw](./tags/raw.md) — unescape template fragment
|
||||||
* [unset](./tags/unset.md) — unset a given variables
|
* [unset](./tags/unset.md) — unset a given variables
|
||||||
* or [add](./ext/extend.md#add-tags) yours
|
* or [add](./ext/extend.md#add-tags) yours
|
||||||
|
|
||||||
|
Deprecated tags
|
||||||
|
|
||||||
|
* [for](./tags/for.md), `forelse`, `break` and `continue` — loop statement
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
Tag {cycle}
|
Tag {cycle}
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
`{cycle}` is used to alternate a set of values.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{for $i=$a.c..}
|
{foreach 1..10}
|
||||||
<div class="{cycle ["odd", "even"]}">
|
<div class="{cycle ["odd", "even"]}">
|
||||||
{/for}
|
{/foreach}
|
||||||
|
|
||||||
|
|
||||||
{for $i=$a.c..}
|
{foreach 1..10}
|
||||||
<div class="{cycle ["odd", "even"] index=$i}">
|
<div class="{cycle ["odd", "even"] index=$i}">
|
||||||
{/for}
|
{/foreach}
|
||||||
```
|
```
|
@ -1,82 +1,68 @@
|
|||||||
Tag {extends} [RU]
|
Tag {extends}
|
||||||
==================
|
=============
|
||||||
|
|
||||||
Тег `{extends}` реализует наследование шаблонов, иерархия, обратная {include}. То есть шаблон сам выбирает своего родителя.
|
`{extends}` tags are used in child templates in template inheritance for extending parent templates.
|
||||||
|
The `{extends}` tag must be on before any block.
|
||||||
|
Also if a child template extends a parent template with the `{extends}` tag it may contain only `{block}` tags. Any other template content is ignored.
|
||||||
|
|
||||||
### {extends}
|
### {extends}
|
||||||
|
|
||||||
Родительский шаблон можно задать единожды и до объявления какого-либо блока.
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{extends 'parent.tpl'}
|
{extends 'parent.tpl'}
|
||||||
```
|
```
|
||||||
|
|
||||||
Имя родительского шаблона может быть задан динамически, в этом случае производительность отрисовки может снизиться.
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{extends $parent_tpl}
|
|
||||||
```
|
|
||||||
|
|
||||||
### {block}
|
### {block}
|
||||||
|
|
||||||
Блок указывает фрагмент шаблона, который будет передан родителю. Имя блока может быть задано как явно
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{block bk1}content 1{/block}
|
|
||||||
...
|
|
||||||
{block 'bk2'}content 2{/block}
|
{block 'bk2'}content 2{/block}
|
||||||
```
|
```
|
||||||
|
|
||||||
так и не явно, но в данном случае пострадает производительность
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{block "bk{$number}"}content {$number}{/block}
|
|
||||||
...
|
|
||||||
{if $condition}
|
|
||||||
{block "bk-if"}content, then 'if' is true{/block}
|
|
||||||
{else}
|
|
||||||
{block "bk{$fail}"}content, then 'if' is false{/block}
|
|
||||||
{/if}
|
|
||||||
```
|
|
||||||
|
|
||||||
### {use}
|
### {use}
|
||||||
|
|
||||||
Что бы импортировать блоки из другого шаблона используйте тег {use}:
|
Что бы импортировать блоки из другого шаблона используйте тег {use}:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{use 'blocks.tpl'}
|
{use 'blocks.tpl'} merge blocks from blocks.tpl template
|
||||||
```
|
|
||||||
|
|
||||||
|
{block 'alpha'} rewrite block alpha from blocks.tpl template, if it exists
|
||||||
|
...
|
||||||
|
{/block}
|
||||||
|
```
|
||||||
|
|
||||||
### {parent}
|
### {parent}
|
||||||
|
|
||||||
Planned. Not supported yet. Feature #5.
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{block 'block1'}
|
{extends 'parent.tpl'}
|
||||||
|
|
||||||
|
{block 'header'}
|
||||||
content ...
|
content ...
|
||||||
{parent}
|
{parent} pase code from block 'header' from parent.tpl
|
||||||
content ...
|
content ...
|
||||||
{/block}
|
{/block}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Performance
|
### {paste}
|
||||||
|
|
||||||
Алгоритм реализации наследования шаблонов может работать в разных режимах, в зависимости от условий.
|
Paste code of any block
|
||||||
Каждый режим имеет свою производительность.
|
|
||||||
|
|
||||||
1. **Максимальная** производительность:
|
```smarty
|
||||||
* Имена шаблонов в теге {extends } заданы явно, без использования переменных и условий.
|
{block 'b1'}
|
||||||
* Имена блоков заданы явно, без использования переменных, условий и не вложены ни в какой другой тег.
|
...
|
||||||
2. **Средняя** производительность:
|
{/block}
|
||||||
* Имена шаблонов в теге {extends } заданы явно, без использования переменных и условий.
|
|
||||||
* Имена блоков заданы **не** явно, с использованием переменныч, условий или могут быть вложенные в другие теги.
|
|
||||||
3. **Низкая** производительность:
|
|
||||||
* Имена шаблонов в теге {extends } заданы **не** явно, с использованием переменных и условий.
|
|
||||||
* Имена блоков заданы явно, без использования переменных, условий и не вложены ни в какой другой тег.
|
|
||||||
4. **Минимальная** производительность:
|
|
||||||
* Имена шаблонов в теге {extends } заданы **не** явно, с использованием переменных и условий.
|
|
||||||
* Имена блоков заданы **не** явно, с использованием переменных, условий или могут быть вложенные в другие теги.
|
|
||||||
|
|
||||||
Режим может идти только на понижение, при изменении условий во время прохождения по иерархии шаблонов.
|
{block 'b2'}
|
||||||
При любом режиме работы не используется буферизация данных, то есть данные выводятся сразу.
|
...
|
||||||
|
{paste 'b1'} paste code from b1
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### {$.block}
|
||||||
|
|
||||||
|
Checks if clock exists
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{if $.block.header}
|
||||||
|
block header exists
|
||||||
|
{/if}
|
||||||
|
```
|
@ -1,10 +1,12 @@
|
|||||||
Tags {filter}
|
Tags {filter}
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Позволяет применить модификаторы на фрагмент шаблона
|
Apply modifier to template area.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{filter|strip_tags|truncate:20}
|
{filter|strip_tags|truncate:20}
|
||||||
Remove all HTML <b>tags</b> and truncate {$text} to 20 symbols
|
Remove all HTML <b>tags</b> and truncate {$text} to 20 symbols
|
||||||
{/filter}
|
{/filter}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Note**: output buffering used. May be used a lot of memory if you output a lot of data.
|
@ -1,5 +1,7 @@
|
|||||||
Tag {foreach} [RU]
|
Tag {foreach}
|
||||||
==================
|
=============
|
||||||
|
|
||||||
|
The tag `{foreach}` construct provides an easy way to iterate over arrays and ranges.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as [$key =>] $value [index=$index] [first=$first] [last=$last]}
|
{foreach $list as [$key =>] $value [index=$index] [first=$first] [last=$last]}
|
||||||
@ -15,7 +17,8 @@ Tag {foreach} [RU]
|
|||||||
|
|
||||||
### {foreach}
|
### {foreach}
|
||||||
|
|
||||||
Перебор значений массива $list
|
On each iteration, the value of the current element is assigned to `$value` and the internal array pointer is
|
||||||
|
advanced by one (so on the next iteration, you'll be looking at the next element).
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as $value}
|
{foreach $list as $value}
|
||||||
@ -23,7 +26,7 @@ Tag {foreach} [RU]
|
|||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Перебор ключей и значений массива $list
|
The next form will additionally assign the current element's key to the `$key` variable on each iteration.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as $key => $value}
|
{foreach $list as $key => $value}
|
||||||
@ -31,47 +34,66 @@ Tag {foreach} [RU]
|
|||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Получение номера (индекса) итерации
|
Gets the current array index, starting with zero.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>№{$value@index}: {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
{foreach $list as $value index=$index}
|
{foreach $list as $value index=$index}
|
||||||
<div>№{$index}: {$value}</div>
|
<div>№{$index}: {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Определение первого элемента
|
Detect first iteration:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>{if $value@first} first item {/if} {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
{foreach $list as $value first=$first}
|
{foreach $list as $value first=$first}
|
||||||
<div>{if $first} first item {/if} {$value}</div>
|
<div>{if $first} first item {/if} {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Переменная `$first` будет иметь значение **TRUE**, если текущая итерация является первой.
|
`$first` is `TRUE` if the current `{foreach}` iteration is first iteration.
|
||||||
Определение последнего элемента
|
|
||||||
|
Detect last iteration:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>{if $value@last} last item {/if} {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
{foreach $list as $value last=$last}
|
{foreach $list as $value last=$last}
|
||||||
<div>{if $last} last item {/if} {$value}</div>
|
<div>{if $last} last item {/if} {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Переменная `$last` будет иметь значение **TRUE**, если текущая итерация является последней.
|
`$last` is set to `TRUE` if the current `{foreach}` iteration is last iteration.
|
||||||
|
|
||||||
### {break}
|
### {break}
|
||||||
|
|
||||||
Тег `{break}` используется для выхода из цикла до достижения последней итерации. Если в цикле встречается тег `{break}`, цикл завершает свою работу, и далее, выполняется код, следующий сразу за блоком цикла
|
Tag `{break}` aborts the iteration.
|
||||||
|
|
||||||
### {continue}
|
### {continue}
|
||||||
|
|
||||||
Тег `{continue}` используется для прерывания текущей итерации. Если в цикле встречается тег `{continue}`, часть цикла, следующая после тега, не выполняется, и начинается следующая итерация. Если текущая итерация была последней, цикл завершается.
|
Tag `{continue}` leaves the current iteration and begins with the next iteration.
|
||||||
|
|
||||||
### {foreachelse}
|
### {foreachelse}
|
||||||
|
|
||||||
Тег {foreachelse} ограничивает код, который должен быть выполнен, если итерируемый объект пуст.
|
`{foreachelse}` is executed when there are no values in the array variable.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{var $list = []}
|
{set $list = []}
|
||||||
{foreach $list as $value}
|
{foreach $list as $value}
|
||||||
<div>{if $last} last item {/if} {$value}</div>
|
<div>{if $last} last item {/if} {$value}</div>
|
||||||
{foreachelse}
|
{foreachelse}
|
||||||
@ -79,8 +101,4 @@ Tag {foreach} [RU]
|
|||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
В блоке `{foreachelse}...{/foreach}` использование `{break}`, `{continue}` выбросит исключение `Fenom\CompileException` при компиляции
|
`{foreachelse}` does not support tags `{break}` and `{continue}`.
|
||||||
|
|
||||||
### Notice
|
|
||||||
|
|
||||||
Использование last требует от `$list` быть **countable**.
|
|
@ -1,7 +1,9 @@
|
|||||||
Tag {if} [RU]
|
Tag {if}
|
||||||
=============
|
========
|
||||||
|
|
||||||
Реализация оператора [if](http://docs.php.net/if) из PHP
|
Tag {if} have much the same flexibility as PHP [if](http://docs.php.net/if) statements,
|
||||||
|
with a few added features for the template engine.
|
||||||
|
All operators, allowed functions and variables are recognized in conditions.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{if <expression>}
|
{if <expression>}
|
||||||
@ -21,8 +23,6 @@ Tag {if} [RU]
|
|||||||
{/if}
|
{/if}
|
||||||
```
|
```
|
||||||
|
|
||||||
Код, расположенный в теге `{if}` будет выполнен/выведен если выражение *<expression>* возвращает значение приводимое к **TRUE**
|
|
||||||
|
|
||||||
### {elseif}
|
### {elseif}
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
@ -33,8 +33,6 @@ Tag {if} [RU]
|
|||||||
{/if}
|
{/if}
|
||||||
```
|
```
|
||||||
|
|
||||||
Код, расположенный после тега `{elseif}` будет выполнен/выведен, если выражение <expression1> вернуло значение приводимое к **FALSE**, <expression2> - приводимое к **TRUE**
|
|
||||||
|
|
||||||
### {else}
|
### {else}
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
@ -43,7 +41,4 @@ Tag {if} [RU]
|
|||||||
{else}
|
{else}
|
||||||
{*...some code...*}
|
{*...some code...*}
|
||||||
{/if}
|
{/if}
|
||||||
```
|
```
|
||||||
|
|
||||||
Код, расположенный после тега `{else}` будет выполнен/выведен, если выражение <expression> вернуло значение приводимое к **FALSE**
|
|
||||||
В тестируемых выражениях могут быть использованы логические операторы , что позволяет обрабатывать сочетания нескольких условий.
|
|
@ -1,12 +1,12 @@
|
|||||||
Tag {macro} [RU]
|
Tag {macro}
|
||||||
================
|
===========
|
||||||
|
|
||||||
Макросы - фрагмент шаблона который можно повторить сколь угодно раз и в каком угодно месте.
|
Macros are comparable with functions in regular programming languages.
|
||||||
Макросы не имеют общего пространства имен с шаблоном и могут оперировать только переданными переменными.
|
They are useful to put often used HTML idioms into reusable elements to not repeat yourself.
|
||||||
|
|
||||||
### {macro}
|
### {macro}
|
||||||
|
|
||||||
Обявление макроса происходит при помощи блочного тега `{macro}`
|
Macros can be defined in any template using tag `{macro}`.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{macro plus($x, $y, $z=0)}
|
{macro plus($x, $y, $z=0)}
|
||||||
@ -14,14 +14,10 @@ Tag {macro} [RU]
|
|||||||
{/macro}
|
{/macro}
|
||||||
```
|
```
|
||||||
|
|
||||||
Вызов макроса происходит при помощи строкового тега `{macro}`. Аргументы передаются стандартно, как атрибуты в HTML тегах
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{macro.plus x=$num y=100}
|
{macro.plus x=$num y=100}
|
||||||
```
|
```
|
||||||
|
|
||||||
Во время рекурсивного вызова используйте суффикс macro что бы обратиться к текущему макросу:
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{macro plus($x, $y, $z=0)}
|
{macro plus($x, $y, $z=0)}
|
||||||
...
|
...
|
||||||
@ -32,13 +28,17 @@ Tag {macro} [RU]
|
|||||||
|
|
||||||
### {import}
|
### {import}
|
||||||
|
|
||||||
Для использования маросов в другом шаблоне необходимо их импортировать при помощи тега `{import}`
|
Macros can be defined in any template, and need to be "imported" before being used.
|
||||||
|
The above import call imports the "math.tpl" file (which can contain only macros, or a template and some macros),
|
||||||
|
and import the functions as items of the `macro` namespace.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{import 'math.tpl'}
|
{import 'math.tpl'}
|
||||||
|
|
||||||
|
{macro.plus x=1 y=3}
|
||||||
```
|
```
|
||||||
|
|
||||||
При импорте можно указать дргое пространство имен что бы можно было использовать одноименные макросы из разных шаблонов
|
Use another namespace instead of `macro`
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{import 'math.tpl' as math}
|
{import 'math.tpl' as math}
|
||||||
@ -46,9 +46,6 @@ Tag {macro} [RU]
|
|||||||
{math.plus x=5 y=100}
|
{math.plus x=5 y=100}
|
||||||
```
|
```
|
||||||
|
|
||||||
Пространство имен макросов может совпадать с названием какого-либо тега, в данном случае ничего плохого не произойдет: будет вызван макрос, а тег не исчезнит
|
|
||||||
При необходимости можно импортировать только необходимые макросы, явно указав в теге `{import}`
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{import [plus, minus, exp] from 'math.tpl' as math}
|
{import [plus, minus, exp] from 'math.tpl' as math}
|
||||||
```
|
```
|
84
docs/en/tags/set.md
Normal file
84
docs/en/tags/set.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
Tag {set}
|
||||||
|
=========
|
||||||
|
|
||||||
|
The tag {set} is used for assigning template variables during the execution of a template.
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $var=EXPR}
|
||||||
|
```
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $var}
|
||||||
|
... any content ...
|
||||||
|
{/set}
|
||||||
|
```
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $var|modifiers}
|
||||||
|
... any content ...
|
||||||
|
{/set}
|
||||||
|
```
|
||||||
|
|
||||||
|
Variable names follow the same rules as other labels in PHP.
|
||||||
|
A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $v = 5}
|
||||||
|
{set $v = "value"}
|
||||||
|
|
||||||
|
{set $v = $x+$y}
|
||||||
|
{set $v = 4}
|
||||||
|
{set $v = $z++ + 1}
|
||||||
|
{set $v = --$z}
|
||||||
|
{set $v = $y/$x}
|
||||||
|
{set $v = $y-$x}
|
||||||
|
{set $v = $y*$x-2}
|
||||||
|
{set $v = ($y^$x)+7}
|
||||||
|
```
|
||||||
|
|
||||||
|
Works this array too
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $v = [1,2,3]}
|
||||||
|
{set $v = []}
|
||||||
|
{set $v = ["one"|upper => 1, 4 => $x, "three" => 3]}
|
||||||
|
{set $v = ["key1" => $y*$x-2, "key2" => ["z" => $z]]}
|
||||||
|
```
|
||||||
|
|
||||||
|
Getting function result into variable
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $v = count([1,2,3])+7}
|
||||||
|
```
|
||||||
|
|
||||||
|
Fetch the output of the template into variable
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $v}
|
||||||
|
Some long {$text|trim}
|
||||||
|
{/set}
|
||||||
|
|
||||||
|
{set $v|escape} {* apply modifier to variable*}
|
||||||
|
Some long {$text|trim}
|
||||||
|
{/set}
|
||||||
|
```
|
||||||
|
|
||||||
|
### {add}
|
||||||
|
|
||||||
|
The tag {add} the same tag as {set} except that sets the value of the variable if it does not exist.
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{add $var = 'value'}
|
||||||
|
```
|
||||||
|
|
||||||
|
instead of
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{if $var is not set}
|
||||||
|
{set $var = 'value'}
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
|
### {var}
|
||||||
|
|
||||||
|
Old name of tag {set}. Currently tag {var} the same tag as {set}.
|
@ -1,64 +0,0 @@
|
|||||||
Tag {var}
|
|
||||||
=========
|
|
||||||
|
|
||||||
The tag {var} is used for assigning template variables during the execution of a template.
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $var=EXPR}
|
|
||||||
```
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $var}
|
|
||||||
... any content ...
|
|
||||||
{/var}
|
|
||||||
```
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $var|modifiers}
|
|
||||||
... any content ...
|
|
||||||
{/var}
|
|
||||||
```
|
|
||||||
|
|
||||||
Variable names follow the same rules as other labels in PHP.
|
|
||||||
A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $v = 5}
|
|
||||||
{var $v = "value"}
|
|
||||||
|
|
||||||
{var $v = $x+$y}
|
|
||||||
{var $v = 4}
|
|
||||||
{var $v = $z++ + 1}
|
|
||||||
{var $v = --$z}
|
|
||||||
{var $v = $y/$x}
|
|
||||||
{var $v = $y-$x}
|
|
||||||
{var $v = $y*$x-2}
|
|
||||||
{var $v = ($y^$x)+7}
|
|
||||||
```
|
|
||||||
|
|
||||||
Creating array
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $v = [1,2,3]}
|
|
||||||
{var $v = []}
|
|
||||||
{var $v = ["one"|upper => 1, 4 => $x, "three" => 3]}
|
|
||||||
{var $v = ["key1" => $y*$x-2, "key2" => ["z" => $z]]}
|
|
||||||
```
|
|
||||||
|
|
||||||
Getting function result into variable
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $v = count([1,2,3])+7}
|
|
||||||
```
|
|
||||||
|
|
||||||
Collect the output of the template into a variable
|
|
||||||
|
|
||||||
```smarty
|
|
||||||
{var $v}
|
|
||||||
Some long {$text|trim}
|
|
||||||
{/var}
|
|
||||||
|
|
||||||
{var $v|escape} {* apply modifier to variable*}
|
|
||||||
Some long {$text|trim}
|
|
||||||
{/var}
|
|
||||||
```
|
|
@ -36,8 +36,9 @@ $fenom->setOptions($options);
|
|||||||
| *force_include* | `Fenom::FORCE_INCLUDE` | стараться по возможности вставить код дочернего шаблона в родительский при подключении шаблона | повышает производительность, увеличивает размер файлов в кеше, уменьшает количество файлов в кеше |
|
| *force_include* | `Fenom::FORCE_INCLUDE` | стараться по возможности вставить код дочернего шаблона в родительский при подключении шаблона | повышает производительность, увеличивает размер файлов в кеше, уменьшает количество файлов в кеше |
|
||||||
| *auto_escape* | `Fenom::AUTO_ESCAPE` | автоматически экранировать HTML сущности при выводе переменных в шаблон | понижает производительность |
|
| *auto_escape* | `Fenom::AUTO_ESCAPE` | автоматически экранировать HTML сущности при выводе переменных в шаблон | понижает производительность |
|
||||||
| *force_verify* | `Fenom::FORCE_VERIFY` | автоматически проверять существование переменной перед использованием в шаблоне | понижает производительность |
|
| *force_verify* | `Fenom::FORCE_VERIFY` | автоматически проверять существование переменной перед использованием в шаблоне | понижает производительность |
|
||||||
| *disable_php_calls* | `Fenom::DENY_PHP_CALLS` | отключает возможность вызова статических методов и функций в шаблоне | |
|
| *disable_call* | `Fenom::DENY_CALL` | отключает возможность вызова статических методов и функций в шаблоне | |
|
||||||
| *disable_statics* | `Fenom::DENY_STATICS` | устаревшее название disable_php_calls | |
|
| *disable_php_calls* | `Fenom::DENY_PHP_CALLS` | устаревшее название disable_call | |
|
||||||
|
| *disable_statics* | `Fenom::DENY_STATICS` | устаревшее название disable_call | |
|
||||||
| *strip* | `Fenom::AUTO_STRIP` | удаляет лишиние пробелы в шаблоне | уменьшает размер кеша |
|
| *strip* | `Fenom::AUTO_STRIP` | удаляет лишиние пробелы в шаблоне | уменьшает размер кеша |
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
@ -135,9 +135,21 @@ Fenom поддерживает префиксные и постфиксные о
|
|||||||
* `$a ~~ $b` - возвращает результат объединения сток `$a` и `$b` через пробел
|
* `$a ~~ $b` - возвращает результат объединения сток `$a` и `$b` через пробел
|
||||||
* `$a ~= $b` - присвоение с объединением
|
* `$a ~= $b` - присвоение с объединением
|
||||||
|
|
||||||
|
Примеры
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{"A" ~ "B"} -> AB
|
||||||
|
|
||||||
|
{"A" ~~ "B"} -> A B
|
||||||
|
|
||||||
|
{add $v = "A"}
|
||||||
|
{set $v ~= "B"}
|
||||||
|
{$v} -> AB
|
||||||
|
```
|
||||||
|
|
||||||
### Оператор интервала
|
### Оператор интервала
|
||||||
|
|
||||||
Оператор `..` позволяет создать массив данных, не выходящие за указанные ограничения.
|
Оператор `..` позволяет создать массив данных, не выходящие за указанные пределы.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{set $a = 1..4}
|
{set $a = 1..4}
|
||||||
|
@ -26,22 +26,27 @@
|
|||||||
|
|
||||||
[Использование](./syntax.md#Теги) тегов.
|
[Использование](./syntax.md#Теги) тегов.
|
||||||
|
|
||||||
* [set](./tags/set.md), `add` и `var` — определение значения переменной
|
* [set](./tags/set.md), [add](./tags/set.md#add) и [var](./tags/set.md#var) — определение значения переменной
|
||||||
* [if](./tags/if.md), `elseif` и `else` — условный оператор
|
* [if](./tags/if.md), [elseif](./tags/if.md#elseif) и [else](./tags/if.md#else) — условный оператор
|
||||||
* [foreach](./tags/foreach.md), `foreachelse`, `break` and `continue` — перебор элементов массива или объекта
|
* [foreach](./tags/foreach.md), [foreachelse](./tags/foreach.md#foreachelse),
|
||||||
* [for](./tags/for.md), `forelse`, `break` and `continue` — цикл
|
[break](./tags/foreach.md#break) и [continue](./tags/foreach.md#continue) — перебор элементов массива или объекта
|
||||||
* [switch](./tags/switch.md), `case` — групповой условный оператор
|
* [switch](./tags/switch.md) и [case](./tags/switch.md#case) — групповой условный оператор
|
||||||
* [cycle](./tags/cycle.md) — циклицеский перебор массива значений
|
* [cycle](./tags/cycle.md) — циклицеский перебор массива значений
|
||||||
* [include](./tags/include.md), `insert` — вставляет и исполняет указанный шаблон
|
* [include](./tags/include.md), [insert](./tags/include.md#insert) — вставляет и исполняет указанный шаблон
|
||||||
* [extends](./tags/extends.md), `use`, `block` и `parent` — [наследование](./inheritance.md) шаблонов
|
* [extends](./tags/extends.md), [use](./tags/extends.md#use),
|
||||||
|
[block](./tags/extends.md#block), [parent](./tags/extends.md#parent) и
|
||||||
|
[paste](./tags/extends.md#paste) — [наследование](./inheritance.md) шаблонов
|
||||||
* [filter](./tags/filter.md) — применение модификаторов к фрагменту шаблона
|
* [filter](./tags/filter.md) — применение модификаторов к фрагменту шаблона
|
||||||
* [ignore](./tags/ignore.md) — игнорирование тегов Fenom
|
* [ignore](./tags/ignore.md) — игнорирование тегов Fenom
|
||||||
* [macro](./tags/macro.md) и `import` — пользовательские функции шаблонов
|
* [macro](./tags/macro.md) и [import](./tags/macro.md#macro) — пользовательские функции шаблонов
|
||||||
* [autoescape](./tags/autoescape.md) — экранирует фрагмент шаблона
|
* [autoescape](./tags/autoescape.md) — экранирует фрагмент шаблона
|
||||||
* [raw](./tags/raw.md) — отключает экранирование фрагмента шаблона
|
* [raw](./tags/raw.md) — отключает экранирование фрагмента шаблона
|
||||||
* [unset](./tags/unset.md) — удаляет переменные
|
* [unset](./tags/unset.md) — удаляет переменные
|
||||||
* или [добавьте](./ext/extend.md#Добавление-тегов) свои
|
* или [добавьте](./ext/extend.md#Добавление-тегов) свои
|
||||||
|
|
||||||
|
Устаревшие теги
|
||||||
|
|
||||||
|
* [for](./tags/for.md), `forelse`, `break` and `continue` — цикл
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
@ -100,9 +100,10 @@
|
|||||||
* `$.const` обращение к PHP константе: `$.const.PHP_EOL` обращение к константе `PHP_EOL`. Поддерживается пространство имен
|
* `$.const` обращение к PHP константе: `$.const.PHP_EOL` обращение к константе `PHP_EOL`. Поддерживается пространство имен
|
||||||
которое разделяется через точку: `$.const.Storage.FS::DIR_SEPARATOR` обращение к PHP константе `Storage\FS::DIR_SEPARATOR`
|
которое разделяется через точку: `$.const.Storage.FS::DIR_SEPARATOR` обращение к PHP константе `Storage\FS::DIR_SEPARATOR`
|
||||||
если такой констатнты нет будет взята константа `Storage\FS\DIR_SEPARATOR`.
|
если такой констатнты нет будет взята константа `Storage\FS\DIR_SEPARATOR`.
|
||||||
* `$.php` обращение к статическомому методу. `$.php.Storage.FS::put($filename, $data)` обращение к методу `Storage\FS::put($filename, $data)`.
|
* `$.call` обращение к статическомому методу. `$.call.Storage.FS::put($filename, $data)` обращение к методу `Storage\FS::put($filename, $data)`.
|
||||||
`$.php.Storage.FS.put($filename, $data)` `Storage\FS\put($filename, $data)`
|
Настройка `disable_call` отключает возможность обращения к `$.call`. Так же можно ограничить и указать список доступных к вызову классов и функций.
|
||||||
* так же вы можете [добавить](./ext/extend.md#Расширение-глобальной-переменной) свои системные переменные и функции
|
* `$.block` проверка на сущестование блоков которые были определены до момента обращения к акцессору. Например, `{$.blocks.BLOCK_NAME}`.
|
||||||
|
* так же вы можете [добавить](./ext/extend.md#Расширение-глобальной-переменной) свои или [удалить](./ext/extend.md#Расширение-глобальной-переменной) существующие системные переменные и функции
|
||||||
|
|
||||||
|
|
||||||
## Скалярные значения
|
## Скалярные значения
|
||||||
@ -156,7 +157,7 @@
|
|||||||
{"Hi, {$user.name}!"} выводит: Hi, Username!
|
{"Hi, {$user.name}!"} выводит: Hi, Username!
|
||||||
{"Hi, {$user->name}!"} выводит: Hi, Username!
|
{"Hi, {$user->name}!"} выводит: Hi, Username!
|
||||||
{"Hi, {$user->getName()}!"} выводит: Hi, Username!
|
{"Hi, {$user->getName()}!"} выводит: Hi, Username!
|
||||||
{"Hi, {\$user->name}!"} выводит: Hi, {\$user->name}!
|
{"Hi, {\$user->name}!"} выводит: Hi, {$user->name}!
|
||||||
```
|
```
|
||||||
|
|
||||||
Допускаются также различные операции и модификаторы:
|
Допускаются также различные операции и модификаторы:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
Тег {extends}
|
Тег `{extends}`
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Тег `{extends}` реализует [наследование](../inheritance.md) шаблонов, иерархия, обратная {include}. То есть шаблон сам выбирает своего родителя.
|
Тег `{extends}` реализует [наследование](../inheritance.md) шаблонов, иерархия, обратная {include}. То есть шаблон сам выбирает своего родителя.
|
||||||
|
|
||||||
### {extends}
|
### `{extends}`
|
||||||
|
|
||||||
Родительский шаблон можно задать единожды и до объявления какого-либо блока.
|
Родительский шаблон можно задать единожды и до объявления какого-либо блока.
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
{extends $parent_tpl}
|
{extends $parent_tpl}
|
||||||
```
|
```
|
||||||
|
|
||||||
### {block}
|
### `{block}`
|
||||||
|
|
||||||
Блок указывает фрагмент шаблона, который будет передан родителю. Имя блока должно быть задано явно:
|
Блок указывает фрагмент шаблона, который будет передан родителю. Имя блока должно быть задано явно:
|
||||||
|
|
||||||
@ -28,7 +28,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### {use}
|
### `{use}`
|
||||||
|
|
||||||
Что бы импортировать блоки из другого шаблона используйте тег {use}:
|
Что бы импортировать блоки из другого шаблона используйте тег {use}:
|
||||||
|
|
||||||
@ -36,7 +36,7 @@
|
|||||||
{use 'blocks.tpl'}
|
{use 'blocks.tpl'}
|
||||||
```
|
```
|
||||||
|
|
||||||
### {parent}
|
### `{parent}`
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{block 'block1'}
|
{block 'block1'}
|
||||||
@ -44,4 +44,26 @@
|
|||||||
{parent}
|
{parent}
|
||||||
content ...
|
content ...
|
||||||
{/block}
|
{/block}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `{paste}`
|
||||||
|
|
||||||
|
Иставка кода блока в любое место через тег `{paste}`
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{block 'b1'}
|
||||||
|
...
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{paste 'b1'}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `{$.block}`
|
||||||
|
|
||||||
|
Проверка наличия блока череж глобальную переменную `$.block`
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{if $.block.header}
|
||||||
|
...
|
||||||
|
{/if}
|
||||||
```
|
```
|
@ -5,7 +5,7 @@
|
|||||||
`Foreach` работает только с массивами, объектами и интервалами.
|
`Foreach` работает только с массивами, объектами и интервалами.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as [$key =>] $value [index=$index] [first=$first] [last=$last]}
|
{foreach $list [as [$key =>] $value] [index=$index] [first=$first] [last=$last]}
|
||||||
{* ...code... *}
|
{* ...code... *}
|
||||||
{break}
|
{break}
|
||||||
{* ...code... *}
|
{* ...code... *}
|
||||||
@ -38,32 +38,51 @@
|
|||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Получение номера (индекса) итерации
|
|
||||||
|
Получение номера (индекса) итерации, начиная с 0
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>№{$value@index}: {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
или
|
||||||
|
|
||||||
{foreach $list as $value index=$index}
|
{foreach $list as $value index=$index}
|
||||||
<div>№{$index}: {$value}</div>
|
<div>№{$index}: {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Определение первого элемента
|
Определение первой итерации:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>{if $value@first} first item {/if} {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
или
|
||||||
|
|
||||||
{foreach $list as $value first=$first}
|
{foreach $list as $value first=$first}
|
||||||
<div>{if $first} first item {/if} {$value}</div>
|
<div>{if $first} first item {/if} {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Переменная `$first` будет иметь значение **TRUE**, если текущая итерация является первой.
|
Переменная `$value@first` будет иметь значение **TRUE**, если текущая итерация является первой.
|
||||||
Определение последнего элемента
|
Определение последней интерации:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
|
{foreach $list as $value}
|
||||||
|
<div>{if $value@last} last item {/if} {$value}</div>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
или
|
||||||
|
|
||||||
{foreach $list as $value last=$last}
|
{foreach $list as $value last=$last}
|
||||||
<div>{if $last} last item {/if} {$value}</div>
|
<div>{if $last} last item {/if} {$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Переменная `$last` будет иметь значение **TRUE**, если текущая итерация является последней.
|
Переменная `$value:last` будет иметь значение **TRUE**, если текущая итерация является последней.
|
||||||
|
|
||||||
**Замечание:**
|
**Замечание:**
|
||||||
Использование `last` требует от `$list` быть **countable**.
|
Использование `last` требует от `$list` быть **countable**.
|
||||||
|
7
example/templates/main.tpl
Normal file
7
example/templates/main.tpl
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
{foreach $list as $item}
|
||||||
|
<ul>
|
||||||
|
<li>{$item#index}: {$item.index}</li>
|
||||||
|
</ul>
|
||||||
|
{/foreach}
|
@ -5,9 +5,12 @@ require_once __DIR__.'/../tests/tools.php';
|
|||||||
|
|
||||||
\Fenom::registerAutoload();
|
\Fenom::registerAutoload();
|
||||||
|
|
||||||
$fenom = Fenom::factory(__DIR__.'/../tests/resources/provider', __DIR__.'/../tests/resources/compile');
|
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/../tests/resources/compile');
|
||||||
$fenom->setOptions(Fenom::AUTO_RELOAD);
|
$fenom->setOptions(Fenom::AUTO_RELOAD);
|
||||||
var_dump($fenom->fetch('extends/auto/parent.tpl'));
|
$fenom->addModifier('firstimg', function ($img) {
|
||||||
|
return $img;
|
||||||
|
});
|
||||||
|
var_dump($fenom->compileCode('{foreach $list as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach}')->getTemplateCode());
|
||||||
//var_dump($fenom->compile("bug158/main.tpl", [])->getTemplateCode());
|
//var_dump($fenom->compile("bug158/main.tpl", [])->getTemplateCode());
|
||||||
//var_dump($fenom->display("bug158/main.tpl", []));
|
//var_dump($fenom->display("bug158/main.tpl", []));
|
||||||
// $fenom->getTemplate("problem.tpl");
|
// $fenom->getTemplate("problem.tpl");
|
2
sandbox/templates/bug215/favicon.tpl
Normal file
2
sandbox/templates/bug215/favicon.tpl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<link rel="apple-touch-icon" sizes="57x57" href="{$path_favicon}apple-touch-icon-57x57.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="60x60" href="{$path_favicon}apple-touch-icon-60x60.png">
|
8
sandbox/templates/bug215/index.tpl
Normal file
8
sandbox/templates/bug215/index.tpl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{include "bug215/favicon.tpl"}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -18,7 +18,7 @@ use Fenom\Template;
|
|||||||
*/
|
*/
|
||||||
class Fenom
|
class Fenom
|
||||||
{
|
{
|
||||||
const VERSION = '2.8';
|
const VERSION = '2.9';
|
||||||
const REV = 1;
|
const REV = 1;
|
||||||
/* Actions */
|
/* Actions */
|
||||||
const INLINE_COMPILER = 1;
|
const INLINE_COMPILER = 1;
|
||||||
@ -167,6 +167,7 @@ class Fenom
|
|||||||
"esplit" => 'Fenom\Modifier::esplit',
|
"esplit" => 'Fenom\Modifier::esplit',
|
||||||
"join" => 'Fenom\Modifier::join',
|
"join" => 'Fenom\Modifier::join',
|
||||||
"in" => 'Fenom\Modifier::in',
|
"in" => 'Fenom\Modifier::in',
|
||||||
|
"range" => 'Fenom\Modifier::range',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,7 +332,11 @@ class Fenom
|
|||||||
'unset' => array(
|
'unset' => array(
|
||||||
'type' => self::INLINE_COMPILER,
|
'type' => self::INLINE_COMPILER,
|
||||||
'parser' => 'Fenom\Compiler::tagUnset'
|
'parser' => 'Fenom\Compiler::tagUnset'
|
||||||
)
|
),
|
||||||
|
'paste' => array( // {include ...}
|
||||||
|
'type' => self::INLINE_COMPILER,
|
||||||
|
'parser' => 'Fenom\Compiler::tagPaste'
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -380,9 +385,11 @@ class Fenom
|
|||||||
'tpl' => 'Fenom\Accessor::tpl',
|
'tpl' => 'Fenom\Accessor::tpl',
|
||||||
'version' => 'Fenom\Accessor::version',
|
'version' => 'Fenom\Accessor::version',
|
||||||
'const' => 'Fenom\Accessor::constant',
|
'const' => 'Fenom\Accessor::constant',
|
||||||
'php' => 'Fenom\Accessor::php',
|
'php' => 'Fenom\Accessor::call',
|
||||||
|
'call' => 'Fenom\Accessor::call',
|
||||||
'tag' => 'Fenom\Accessor::Tag',
|
'tag' => 'Fenom\Accessor::Tag',
|
||||||
'fetch' => 'Fenom\Accessor::Fetch',
|
'fetch' => 'Fenom\Accessor::fetch',
|
||||||
|
'block' => 'Fenom\Accessor::block',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,7 +138,7 @@ class Accessor {
|
|||||||
* @param Template $tpl
|
* @param Template $tpl
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function php(Tokenizer $tokens, Template $tpl)
|
public static function call(Tokenizer $tokens, Template $tpl)
|
||||||
{
|
{
|
||||||
$callable = array($tokens->skip('.')->need(Tokenizer::MACRO_STRING)->getAndNext());
|
$callable = array($tokens->skip('.')->need(Tokenizer::MACRO_STRING)->getAndNext());
|
||||||
while($tokens->is('.')) {
|
while($tokens->is('.')) {
|
||||||
@ -192,4 +192,21 @@ class Accessor {
|
|||||||
$tokens->skip(')');
|
$tokens->skip(')');
|
||||||
return '$tpl->getStorage()->fetch('.$name.', '.$vars.')';
|
return '$tpl->getStorage()->fetch('.$name.', '.$vars.')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessor {$.block.NAME}
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Template $tpl
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function block(Tokenizer $tokens, Template $tpl)
|
||||||
|
{
|
||||||
|
if($tokens->is('.')) {
|
||||||
|
$name = $tokens->next()->get(Tokenizer::MACRO_STRING);
|
||||||
|
$tokens->next();
|
||||||
|
return isset($tpl->blocks[$name]) ? 'true' : 'false';
|
||||||
|
} else {
|
||||||
|
return "array(".implode(",", array_keys($tpl->blocks)).")";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@
|
|||||||
namespace Fenom;
|
namespace Fenom;
|
||||||
|
|
||||||
use Doctrine\Instantiator\Exception\InvalidArgumentException;
|
use Doctrine\Instantiator\Exception\InvalidArgumentException;
|
||||||
|
use Fenom\Error\CompileException;
|
||||||
use Fenom\Error\InvalidUsageException;
|
use Fenom\Error\InvalidUsageException;
|
||||||
use Fenom\Error\UnexpectedTokenException;
|
use Fenom\Error\UnexpectedTokenException;
|
||||||
|
|
||||||
@ -132,70 +133,53 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function foreachOpen(Tokenizer $tokens, Tag $scope)
|
public static function foreachOpen(Tokenizer $tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
$p = array("index" => false, "first" => false, "last" => false);
|
$scope["else"] = false;
|
||||||
$key = null;
|
$scope["key"] = null;
|
||||||
$before = $body = array();
|
$scope["prepend"] = "";
|
||||||
$prepend = "";
|
$scope["before"] = array();
|
||||||
if ($tokens->is('[')) {
|
$scope["after"] = array();
|
||||||
|
$scope["body"] = array();
|
||||||
|
|
||||||
|
if ($tokens->is('[')) { // array
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$from = $scope->tpl->parseArray($tokens, $count);
|
$scope['from'] = $scope->tpl->parseArray($tokens, $count);
|
||||||
$check = $count;
|
$scope['check'] = $count;
|
||||||
} else {
|
$scope["var"] = $scope->tpl->tmpVar();
|
||||||
$from = $scope->tpl->parseExpr($tokens, $is_var);
|
$scope['prepend'] = $scope["var"].' = '.$scope['from'].';';
|
||||||
|
$scope['from'] = $scope["var"];
|
||||||
|
} else { // expression
|
||||||
|
$scope['from'] = $scope->tpl->parseExpr($tokens, $is_var);
|
||||||
if($is_var) {
|
if($is_var) {
|
||||||
$check = '!empty('.$from.') && (is_array('.$from.') || '.$from.' instanceof \Traversable)';
|
$scope['check'] = '!empty('.$scope['from'].') && (is_array('.$scope['from'].') || '.$scope['from'].' instanceof \Traversable)';
|
||||||
} else {
|
} else {
|
||||||
$scope["var"] = $scope->tpl->tmpVar();
|
$scope["var"] = $scope->tpl->tmpVar();
|
||||||
$prepend = $scope["var"].' = '.$from.';';
|
$scope['prepend'] = $scope["var"].' = '.$scope['from'].';';
|
||||||
$from = $scope["var"];
|
$scope['from'] = $scope["var"];
|
||||||
$check = 'is_array('.$from.') && count('.$from.') || ('.$from.' instanceof \Traversable)';
|
$scope['check'] = 'is_array('.$scope['from'].') && count('.$scope['from'].') || ('.$scope['from'].' instanceof \Traversable)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$tokens->get(T_AS);
|
if($tokens->is(T_AS)) {
|
||||||
$tokens->next();
|
|
||||||
$value = $scope->tpl->parseVariable($tokens);
|
|
||||||
if ($tokens->is(T_DOUBLE_ARROW)) {
|
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$key = $value;
|
|
||||||
$value = $scope->tpl->parseVariable($tokens);
|
$value = $scope->tpl->parseVariable($tokens);
|
||||||
|
if ($tokens->is(T_DOUBLE_ARROW)) {
|
||||||
|
$tokens->next();
|
||||||
|
$scope["key"] = $value;
|
||||||
|
$scope["value"] = $scope->tpl->parseVariable($tokens);
|
||||||
|
} else {
|
||||||
|
$scope["value"] = $value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$scope["value"] = '$_un';
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope["after"] = array();
|
|
||||||
$scope["else"] = false;
|
|
||||||
|
|
||||||
while ($token = $tokens->key()) {
|
while ($token = $tokens->key()) {
|
||||||
$param = $tokens->get(T_STRING);
|
$param = $tokens->get(T_STRING);
|
||||||
if (!isset($p[$param])) {
|
$var_name = self::foreachProp($scope, $param);
|
||||||
throw new InvalidUsageException("Unknown parameter '$param' in {foreach}");
|
|
||||||
}
|
|
||||||
$tokens->getNext("=");
|
$tokens->getNext("=");
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$p[$param] = $scope->tpl->parseVariable($tokens);
|
$scope['before'][] = $scope->tpl->parseVariable($tokens)." = &". $var_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($p["index"]) {
|
return '';
|
||||||
$before[] = $p["index"] . ' = 0';
|
|
||||||
$scope["after"][] = $p["index"] . '++';
|
|
||||||
}
|
|
||||||
if ($p["first"]) {
|
|
||||||
$before[] = $p["first"] . ' = true';
|
|
||||||
$scope["after"][] = $p["first"] . ' && (' . $p["first"] . ' = false )';
|
|
||||||
}
|
|
||||||
if ($p["last"]) {
|
|
||||||
$before[] = $p["last"] . ' = false';
|
|
||||||
$scope["uid"] = "v" . $scope->tpl->i++;
|
|
||||||
$before[] = '$' . $scope["uid"] . " = count($from)";
|
|
||||||
$body[] = 'if(!--$' . $scope["uid"] . ') ' . $p["last"] . ' = true';
|
|
||||||
}
|
|
||||||
|
|
||||||
$before = $before ? implode("; ", $before) . ";" : "";
|
|
||||||
$body = $body ? implode("; ", $body) . ";" : "";
|
|
||||||
$scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
|
||||||
if ($key) {
|
|
||||||
return "$prepend if($check) {\n $before foreach($from as $key => $value) { $body";
|
|
||||||
} else {
|
|
||||||
return "$prepend if($check) {\n $before foreach($from as $value) { $body";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,7 +192,40 @@ class Compiler
|
|||||||
public static function foreachElse($tokens, Tag $scope)
|
public static function foreachElse($tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
$scope["no-break"] = $scope["no-continue"] = $scope["else"] = true;
|
$scope["no-break"] = $scope["no-continue"] = $scope["else"] = true;
|
||||||
return " {$scope['after']} } } else {";
|
$after = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
||||||
|
return " {$after} } } else {";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $scope
|
||||||
|
* @param string $prop
|
||||||
|
* @return string
|
||||||
|
* @throws CompileException
|
||||||
|
*/
|
||||||
|
public static function foreachProp(Tag $scope, $prop) {
|
||||||
|
if(empty($scope["props"][$prop])) {
|
||||||
|
$var_name = $scope["props"][$prop] = $scope->tpl->tmpVar()."_".$prop;
|
||||||
|
switch($prop) {
|
||||||
|
case "index":
|
||||||
|
$scope["before"][] = $var_name . ' = 0';
|
||||||
|
$scope["after"][] = $var_name . '++';
|
||||||
|
break;
|
||||||
|
case "first":
|
||||||
|
$scope["before"][] = $var_name . ' = true';
|
||||||
|
$scope["after"][] = $var_name . ' && (' . $var_name . ' = false )';
|
||||||
|
break;
|
||||||
|
case "last":
|
||||||
|
$scope["before"][] = $var_name . ' = false';
|
||||||
|
$scope["uid"] = $scope->tpl->tmpVar();
|
||||||
|
$scope["before"][] = $scope["uid"] . " = count({$scope["from"]})";
|
||||||
|
$scope["body"][] = 'if(!--' . $scope["uid"] . ') ' . $var_name . ' = true';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new CompileException("Unknown foreach property '$prop'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $scope["props"][$prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,10 +238,20 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function foreachClose($tokens, Tag $scope)
|
public static function foreachClose($tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
|
$before = $scope["before"] ? implode("; ", $scope["before"]) . ";" : "";
|
||||||
|
$head = $scope["body"] ? implode("; ", $scope["body"]) . ";" : "";
|
||||||
|
$body = $scope->getContent();
|
||||||
|
if ($scope["key"]) {
|
||||||
|
$code = "<?php {$scope["prepend"]} if({$scope["check"]}) {\n $before foreach({$scope["from"]} as {$scope["key"]} => {$scope["value"]}) { $head?>$body";
|
||||||
|
} else {
|
||||||
|
$code = "<?php {$scope["prepend"]} if({$scope["check"]}) {\n $before foreach({$scope["from"]} as {$scope["value"]}) { $head?>$body";
|
||||||
|
}
|
||||||
|
$scope->replaceContent($code);
|
||||||
if ($scope["else"]) {
|
if ($scope["else"]) {
|
||||||
return '}';
|
return '}';
|
||||||
} else {
|
} else {
|
||||||
return " {$scope['after']} } }";
|
$after = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
||||||
|
return " {$after} } }";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,9 +600,6 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function tagBlockOpen(Tokenizer $tokens, Tag $scope)
|
public static function tagBlockOpen(Tokenizer $tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
if ($scope->level > 0) {
|
|
||||||
$scope->tpl->_compatible = true;
|
|
||||||
}
|
|
||||||
$scope["cname"] = $scope->tpl->parsePlainArg($tokens, $name);
|
$scope["cname"] = $scope->tpl->parsePlainArg($tokens, $name);
|
||||||
if (!$name) {
|
if (!$name) {
|
||||||
throw new \RuntimeException("Invalid block name");
|
throw new \RuntimeException("Invalid block name");
|
||||||
@ -1044,4 +1068,15 @@ class Compiler
|
|||||||
}
|
}
|
||||||
return 'unset('.implode(", ", $unset).')';
|
return 'unset('.implode(", ", $unset).')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function tagPaste(Tokenizer $tokens, Tag $tag)
|
||||||
|
{
|
||||||
|
$name = $tokens->get(T_CONSTANT_ENCAPSED_STRING);
|
||||||
|
$tokens->next();
|
||||||
|
if(isset($tag->tpl->blocks[$name])) {
|
||||||
|
return "?>".substr($tag->tpl->blocks[$name]["block"], 1, -1)."<?php ";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,10 +284,13 @@ class Modifier
|
|||||||
* @param string|int $from
|
* @param string|int $from
|
||||||
* @param string|int $to
|
* @param string|int $to
|
||||||
* @param int $step
|
* @param int $step
|
||||||
* @return array
|
* @return RangeIterator
|
||||||
*/
|
*/
|
||||||
public static function range($from, $to, $step = 1) {
|
public static function range($from, $to, $step = 1) {
|
||||||
$v = range($from, $to, $step);
|
if($from instanceof RangeIterator) {
|
||||||
return $v ? $v : array();
|
return $from->setStep($to);
|
||||||
|
} else {
|
||||||
|
return new RangeIterator($from, $to, $step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
102
src/Fenom/RangeIterator.php
Normal file
102
src/Fenom/RangeIterator.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fenom;
|
||||||
|
|
||||||
|
|
||||||
|
class RangeIterator implements \Iterator, \Countable
|
||||||
|
{
|
||||||
|
|
||||||
|
public $current;
|
||||||
|
public $index = 0;
|
||||||
|
public $min;
|
||||||
|
public $max;
|
||||||
|
public $step;
|
||||||
|
|
||||||
|
public function __construct($min, $max, $step = 1)
|
||||||
|
{
|
||||||
|
$this->min = $min;
|
||||||
|
$this->max = $max;
|
||||||
|
$this->setStep($step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $step
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setStep($step) {
|
||||||
|
if($step > 0) {
|
||||||
|
$this->current = min($this->min, $this->max);
|
||||||
|
} elseif($step < 0) {
|
||||||
|
$this->current = max($this->min, $this->max);
|
||||||
|
} else {
|
||||||
|
$step = $this->max - $this->min;
|
||||||
|
$this->current = $this->min;
|
||||||
|
}
|
||||||
|
$this->step = $step;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current element
|
||||||
|
*/
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
return $this->current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move forward to next element
|
||||||
|
*/
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->current += $this->step;
|
||||||
|
$this->index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the key of the current element
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if current position is valid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return $this->current >= $this->min && $this->current <= $this->max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewind the Iterator to the first element
|
||||||
|
*/
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
if($this->step > 0) {
|
||||||
|
$this->current = min($this->min, $this->max);
|
||||||
|
} else {
|
||||||
|
$this->current = max($this->min, $this->max);
|
||||||
|
}
|
||||||
|
$this->index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count elements of an object
|
||||||
|
*/
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return intval(($this->max - $this->min) / $this->step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return "[".implode(", ", range($this->min, $this->max, $this->step))."]";
|
||||||
|
}
|
||||||
|
}
|
@ -219,7 +219,7 @@ class Tag extends \ArrayObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return content of block
|
* Returns tag's content
|
||||||
*
|
*
|
||||||
* @throws \LogicException
|
* @throws \LogicException
|
||||||
* @return string
|
* @return string
|
||||||
@ -230,7 +230,7 @@ class Tag extends \ArrayObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cut scope content
|
* Cut tag's content
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws \LogicException
|
* @throws \LogicException
|
||||||
@ -243,7 +243,7 @@ class Tag extends \ArrayObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace scope content
|
* Replace tag's content
|
||||||
*
|
*
|
||||||
* @param $new_content
|
* @param $new_content
|
||||||
*/
|
*/
|
||||||
|
@ -314,12 +314,12 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate temporary internal template variable
|
* Generate name of temporary internal template variable (may be random)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function tmpVar()
|
public function tmpVar()
|
||||||
{
|
{
|
||||||
return sprintf('$t%x_%x', $this->_crc, $this->i++);
|
return sprintf('$t%x_%x', $this->_crc ? $this->_crc : mt_rand(0, 0x7FFFFFFF), $this->i++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -892,7 +892,7 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
if(($allows & self::TERM_RANGE) && $tokens->is('.') && $tokens->isNext('.')) {
|
if(($allows & self::TERM_RANGE) && $tokens->is('.') && $tokens->isNext('.')) {
|
||||||
$tokens->next()->next();
|
$tokens->next()->next();
|
||||||
$code = 'range('.$code.', '.$this->parseTerm($tokens, $var, self::TERM_MODS).')';
|
$code = '(new \Fenom\RangeIterator('.$code.', '.$this->parseTerm($tokens, $var, self::TERM_MODS).'))';
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
}
|
}
|
||||||
return $code;
|
return $code;
|
||||||
@ -918,7 +918,7 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse variable name: $a, $a.b, $a.b['c']
|
* Parse variable name: $a, $a.b, $a.b['c'], $a:index
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param $var
|
* @param $var
|
||||||
* @return string
|
* @return string
|
||||||
@ -927,8 +927,19 @@ class Template extends Render
|
|||||||
public function parseVariable(Tokenizer $tokens, $var = null)
|
public function parseVariable(Tokenizer $tokens, $var = null)
|
||||||
{
|
{
|
||||||
if (!$var) {
|
if (!$var) {
|
||||||
$var = '$var["' . substr($tokens->get(T_VARIABLE), 1) . '"]';
|
if($tokens->isNext('@')) {
|
||||||
$tokens->next();
|
// $v = $tokens->get(T_VARIABLE);
|
||||||
|
$prop = $tokens->next()->next()->get(T_STRING);
|
||||||
|
if($tag = $this->getParentScope("foreach")) {
|
||||||
|
$tokens->next();
|
||||||
|
return Compiler::foreachProp($tag, $prop);
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$var = '$var["' . substr($tokens->get(T_VARIABLE), 1) . '"]';
|
||||||
|
$tokens->next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while ($t = $tokens->key()) {
|
while ($t = $tokens->key()) {
|
||||||
if ($t === ".") {
|
if ($t === ".") {
|
||||||
|
@ -10,25 +10,26 @@ class SandboxTest extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
return;
|
// return;
|
||||||
$this->fenom->setOptions(\Fenom::FORCE_VERIFY);
|
// $this->fenom->setOptions(\Fenom::FORCE_VERIFY);
|
||||||
$this->fenom->addAccessorSmart('q', 'Navi::$q', \Fenom::ACCESSOR_VAR);
|
// $this->fenom->addAccessorSmart('q', 'Navi::$q', \Fenom::ACCESSOR_VAR);
|
||||||
// $this->assertEquals([1, 2, 4, "as" => 767, "df" => ["qert"]], [1, 2, 4, "as" => 767, "df" => ["qet"]]);
|
// $this->assertEquals([1, 2, 4, "as" => 767, "df" => ["qert"]], [1, 2, 4, "as" => 767, "df" => ["qet"]]);
|
||||||
// $this->fenom->addBlockCompiler('php', 'Fenom\Compiler::nope', function ($tokens, Tag $tag) {
|
// $this->fenom->addBlockCompiler('php', 'Fenom\Compiler::nope', function ($tokens, Tag $tag) {
|
||||||
// return '<?php ' . $tag->cutContent();
|
// return '<?php ' . $tag->cutContent();
|
||||||
// });
|
// });
|
||||||
// $this->tpl('welcome.tpl', '{$a}');
|
// $this->tpl('welcome.tpl', '{$a}');
|
||||||
// var_dump($this->fenom->compileCode('{set $a=$one|min:0..$three|max:4}')->getBody());
|
// var_dump($this->fenom->compileCode('{set $a=$one|min:0..$three|max:4}')->getBody());
|
||||||
try {
|
|
||||||
var_dump($this->fenom->compileCode('{set $.q.ddqd->d() = 333}')->getBody());
|
// try {
|
||||||
} catch (\Exception $e) {
|
// var_dump($this->fenom->compileCode('{foreach $a as $k}A{$k:first}{foreachelse}B{/foreach}')->getBody());
|
||||||
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
// } catch (\Exception $e) {
|
||||||
while ($e->getPrevious()) {
|
// print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
$e = $e->getPrevious();
|
// while ($e->getPrevious()) {
|
||||||
print_r("\n\n" . $e->getMessage() . " in {$e->getFile()}:{$e->getLine()}\n" . $e->getTraceAsString());
|
// $e = $e->getPrevious();
|
||||||
}
|
// print_r("\n\n" . $e->getMessage() . " in {$e->getFile()}:{$e->getLine()}\n" . $e->getTraceAsString());
|
||||||
}
|
// }
|
||||||
exit;
|
// }
|
||||||
|
// exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -696,11 +696,11 @@ class TemplateTest extends TestCase
|
|||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected end of expression"
|
"Unexpected end of expression"
|
||||||
),
|
),
|
||||||
array(
|
// array(
|
||||||
'Foreach: {foreach $list} {$e}, {/foreach} end',
|
// 'Foreach: {foreach $list} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
// 'Fenom\Error\CompileException',
|
||||||
"Unexpected end of expression"
|
// "Unexpected end of expression"
|
||||||
),
|
// ),
|
||||||
// array(
|
// array(
|
||||||
// 'Foreach: {foreach $list+1 as $e} {$e}, {/foreach} end',
|
// 'Foreach: {foreach $list+1 as $e} {$e}, {/foreach} end',
|
||||||
// 'Fenom\Error\CompileException',
|
// 'Fenom\Error\CompileException',
|
||||||
@ -754,7 +754,7 @@ class TemplateTest extends TestCase
|
|||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $e unknown=1} {$e}, {/foreach} end',
|
'Foreach: {foreach $list as $e unknown=1} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unknown parameter 'unknown'"
|
"Unknown foreach property 'unknown'"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $e index=$i+1} {$e}, {/foreach} end',
|
'Foreach: {foreach $list as $e index=$i+1} {$e}, {/foreach} end',
|
||||||
@ -1316,6 +1316,7 @@ class TemplateTest extends TestCase
|
|||||||
return array(
|
return array(
|
||||||
array('Foreach: {foreach $list as $e} {$e}, {/foreach} end', $a, 'Foreach: one, two, three, end'),
|
array('Foreach: {foreach $list as $e} {$e}, {/foreach} end', $a, 'Foreach: one, two, three, end'),
|
||||||
array('Foreach: {foreach $list as $e} {$e},{break} break {/foreach} end', $a, 'Foreach: one, end'),
|
array('Foreach: {foreach $list as $e} {$e},{break} break {/foreach} end', $a, 'Foreach: one, end'),
|
||||||
|
array('Foreach: {foreach $list} 1, {/foreach} end', $a, 'Foreach: 1, 1, 1, end'),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $e} {$e},{continue} continue {/foreach} end',
|
'Foreach: {foreach $list as $e} {$e},{continue} continue {/foreach} end',
|
||||||
$a,
|
$a,
|
||||||
@ -1350,11 +1351,21 @@ class TemplateTest extends TestCase
|
|||||||
$a,
|
$a,
|
||||||
'Foreach: 0: one, 1: two, 2: three, end'
|
'Foreach: 0: one, 1: two, 2: three, end'
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $e} {$e@index}: {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 0: one, 1: two, 2: three, end'
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $k => $e index=$i} {$i}: {$k} => {$e}, {/foreach} end',
|
'Foreach: {foreach $list as $k => $e index=$i} {$i}: {$k} => {$e}, {/foreach} end',
|
||||||
$a,
|
$a,
|
||||||
'Foreach: 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
'Foreach: 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e} {$e@index}: {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $empty as $k => $e index=$i} {$i}: {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
'Foreach: {foreach $empty as $k => $e index=$i} {$i}: {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
||||||
$a,
|
$a,
|
||||||
@ -1365,11 +1376,21 @@ class TemplateTest extends TestCase
|
|||||||
$a,
|
$a,
|
||||||
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e} {if $e@first}first{/if} {$e@index}: {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
'Foreach: {foreach $list as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
||||||
$a,
|
$a,
|
||||||
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e} {if $e@first}first{/if} {$e@index}: {$k} => {$e}, {if $e@last}last{/if} {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $empty as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {foreachelse} empty {/foreach} end',
|
'Foreach: {foreach $empty as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {foreachelse} empty {/foreach} end',
|
||||||
$a,
|
$a,
|
||||||
@ -1566,9 +1587,9 @@ class TemplateTest extends TestCase
|
|||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('{set $a=1..3}', "1,2,3,"),
|
array('{set $a=1..3}', "1,2,3,"),
|
||||||
array('{set $a="a".."f"}', "a,b,c,d,e,f,"),
|
// array('{set $a="a".."f"}', "a,b,c,d,e,f,"),
|
||||||
array('{set $a=1.."f"}', "1,0,"),
|
// array('{set $a=1.."f"}', "1,0,"),
|
||||||
array('{set $a="a"..2}', "0,1,2,"),
|
// array('{set $a="a"..2}', "0,1,2,"),
|
||||||
array('{set $a=$one..$three}', "1,2,3,"),
|
array('{set $a=$one..$three}', "1,2,3,"),
|
||||||
array('{set $a=$one..3}', "1,2,3,"),
|
array('{set $a=$one..3}', "1,2,3,"),
|
||||||
array('{set $a=1..$three}', "1,2,3,"),
|
array('{set $a=1..$three}', "1,2,3,"),
|
||||||
@ -1576,16 +1597,28 @@ class TemplateTest extends TestCase
|
|||||||
array('{set $a=$one..++$three}', "1,2,3,4,"),
|
array('{set $a=$one..++$three}', "1,2,3,4,"),
|
||||||
array('{set $a=$one--..$three++}', "1,2,3,"),
|
array('{set $a=$one--..$three++}', "1,2,3,"),
|
||||||
array('{set $a=--$one..++$three}', "0,1,2,3,4,"),
|
array('{set $a=--$one..++$three}', "0,1,2,3,4,"),
|
||||||
array('{set $a="a"|up.."f"|up}', "A,B,C,D,E,F,"),
|
// array('{set $a="a"|up.."f"|up}', "A,B,C,D,E,F,"),
|
||||||
array('{set $a=$one|min:0..$three|max:4}', "0,1,2,3,4,"),
|
array('{set $a=$one|min:0..$three|max:4}', "0,1,2,3,4,"),
|
||||||
array('{set $a=$one|min:0..4}', "0,1,2,3,4,"),
|
array('{set $a=$one|min:0..4}', "0,1,2,3,4,"),
|
||||||
array('{set $a=0..$three|max:4}', "0,1,2,3,4,"),
|
array('{set $a=0..$three|max:4}', "0,1,2,3,4,"),
|
||||||
|
array('{set $a=0..$three|max:4}', "0,1,2,3,4,"),
|
||||||
|
|
||||||
|
array('{set $a=range(1,3)}', "1,2,3,"),
|
||||||
|
array('{set $a=range(1,3, 2)}', "1,3,"),
|
||||||
|
array('{set $a=range(1..3, 2)}', "1,3,"),
|
||||||
|
array('{set $a=range(1..3, 3)}', "1,"),
|
||||||
|
|
||||||
|
array('{set $a=range(1,3, -1)}', "3,2,1,"),
|
||||||
|
array('{set $a=range(1,3, -2)}', "3,1,"),
|
||||||
|
array('{set $a=range(1..3, -2)}', "3,1,"),
|
||||||
|
array('{set $a=range(1..3, -3)}', "3,"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerRange
|
* @dataProvider providerRange
|
||||||
* @group testRange
|
* @group testRange
|
||||||
|
* @group dev
|
||||||
* @param string $code
|
* @param string $code
|
||||||
* @param string $result
|
* @param string $result
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user