Глава 7. Контексты

Начиная с версии 0.4 в Blitz практически без изменений была добавлена функциональность движка php_templates. Суть контекстов заключается в следующем. Обычно мы имеем дело с «плоскими» шаблонами, в них есть либо переменные, либо какие-то операторы или вызовы, которые обязательно исполняются. Контексты - это подшаблоны, которые не используются до тех пор, пока контроллер шаблона явно это не укажет. Например, если у нас есть php-код

переменная: <?=$a?>, метод: <?=b()?> 

, то оба куска этого кода будут всегда исполнены. Никакой иерархии нет, все php-шаблоны плоские. Теперь рассмотрим некий псевдокод с контекстами

переменная : {{ $a }}, контекст {{ BEGIN b }} что-то внутри {{ END }}

Здесь b — это контекст, который по умолчанию не будет использован (чаще используют термин «итерирован») - и вместо кода от BEGIN до END ничего не будет. Если контекст итерирован один раз, то в шаблоне появится результат исполнения внутренней части контекста. Если проитерировать дважды — результат исполнения внутренней части контекста два раза. Параметры у каждой итерации, разумеется, могут быть разными. Таким образом, для отображения списков достаточно просто итерировать контекст, описывающий элемент списка, для каждого элемента. Самое удобное заключается в том, что контексты могут быть вложены друг в друга. Каждый контекст однозначно определён своим путем — /root/node/item означает, что есть контекст root, внутри которого контекст node внутри которого item. Если итерировать родительский контекст с одними параметрами, потом вложенные контексты, потом снова родительские контексты с другими параметрами, а потом снова вложенные, то можно при помощи одного единственного шаблона сделать страницу абсолютно любой сложности. Есть базовые операции с контекстами — установить текущий контекст и итерировать контекст. Установка означает, что все вызовы по умолчанию работают с этим контекстом, тут есть хорошая аналогия с работой командной оболочке — установить текущий контекст в /root/node/item по смыслу то же самое что сделать cd в /root/node/item. А итерировать фактически означает «исполнить».

Передавая параметр context_path в любую из функций, вы можете передавать его в двух формах:

В Blitz внутри контекстов также доступны такие приятные мелочи как if(), include() и вызов пользовательского метода.

Следующий код выводит ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах.

Пример 7.1. Ужасно доставшее всех знакомое всем приветствие, запрятанное в трех вложенных контекстах

{{ BEGIN root }}
  {{ BEGIN node }}
    {{ BEGIN item }}
        hello, world
    {{ END }}
  {{ END }}
{{ END }}
<?

$T = new Blitz('tpl');
$T->iterate('/root/node/item');
echo $T->parse();

?>
hello, world

Пример 7.2. Работа с простыми списками

{{ BEGIN row }}row #{{ $i }}
{{ END }}
<?

$T = new Blitz('tpl');

$max_num_list = 5;

// use context & iterate
$T->context('row');
for($i=0; $i<$max_num_list; $i++) {
    $T->iterate();
    $T->set(array('i' => $i));
}

// or just use block
for($i=0; $i<$max_num_list; $i++) {
    $T->block('/row',array('i' => $i));
}

echo $T->parse();

?>
row #0
row #1
row #2
row #3
row #4
row #0
row #1
row #2
row #3
row #4

Метод block() — удобная замена последовательным iterate() и set(), которые встречаются в коде очень часто именно вместе. Разумеется, в Blitz внутри контекста можно использовать и include(), и if(), и пользовательские методы. Переменные, установленные в родительских контекстах, «не видны» в дочерних. Если есть необходимость в глобальных переменных, которые будут «видны» в любом месте шаблона - можно использовать метод set_global() вместо set().

Пример 7.3. Как при помощи вложенных контекстов строить более сложные списки

complex list example
{{ BEGIN list; }}
list #{{ $list_num }}
{{ BEGIN list_empty; }} this list is empty {{ END }}{{ BEGIN list_item; }} row #{{ $i_row; }}
{{ END }}
{{ END }}
<?

$T = new Blitz('tpl');

$max_num_list = 5;
$max_num_item = 5;

$T->context('/list');
for($i=0; $i<$max_num_list; $i++) {
    $T->block('',array('list_num' => $i));
    $is_empty = $i%2; // emulate empty sub-lists

    if($is_empty) {
        $T->block('list_empty');
    } else {
        for($j=0; $j<$max_num_item; $j++) {
           $T->block('list_item',array('i_row' => $i.':'.$j));
        }
    }
}

echo $T->parse();

?>
complex list example

list #0
 row #0:0
 row #0:1
 row #0:2
 row #0:3
 row #0:4


list #1
 this list is empty

list #2
 row #2:0
 row #2:1
 row #2:2
 row #2:3
 row #2:4


list #3
 this list is empty

list #4
 row #4:0
 row #4:1
 row #4:2
 row #4:3
 row #4:4

Фактически на этом простом механизме попеременных итераций вложенных контекстов реализуется абсолютно любая логика даже в одном единственном шаблоне.

В-общем, функционал контекстов достаточно мощный для того, что бы использовать шаблонный движок для сколь угодно сложных проектов.