Fetcher-ы используются для получения данных непосредственно из WACT-шаблонов.
Два слова о том, что такое fetcher-ы. Это такие классы, которые реализуют интерфейс WactFetcher или наследники от lmbFetcher класса, которые поддерживают метод fetch(). Этот метод всегда должен возвращать итератор (это важно!).
В шаблонах fetcher-ы используются для получения данных через тег <fetch>. Другой тег <active_record:fetch>, который должен быть вам знаком по базовому туториалу и по разделу "Использование ACTIVE_RECORD"", является аналогом тега <fetch>. Класс тега <active_record:fetch> наследуется от класса тега <fetch>, но первый по-умолчанию использует класс lmbActiveRecordFetcher (limb/web_app/src/fetcher/lmbActiveRecordFetcher.class.php) для получения данных.
То есть fetcher-ы нужны чтобы делать запросы на получение каких-либо данных прямо из шаблонов.
Fetcher-ы могут содержать различные методы, которыми их можно параметрировать. Эти методы имеют вид setSomeParam($value). По-умолчанию fetcher-ы поддерживают следующие методы:
Различные fetcher-ы поддерживают другие методы для задания параметров, например, класс lmbActiveRecordFetcher поддерживает методы setRecordId(), setRecordIds, setFind().
В шаблонах для задания параметров fetcher-ов используется тег <fetch:param>, каждый атрибут которого преобразуется в вызов метода вида setParamName($param_value).
Пусть нам необходимо получить итератор с данными. Допустим, что мы будем использовать особый fetcher - NewsFetcher, который, допустим, возвращает список новостей. :
<fetch using='src/fetcher/NewsFetcher' target='news' /> <list:list id='news'> <table> <list:item> <tr><td>{$date}</td><td>{$title}</td></tr> </list:item> </table> </list:list>
Атрибут тега using указывает на путь до класса fetcher-а(обычно такие классы кладутся в папку src/fetcher/ проекта).
Атрибут target указывает, куда необходимо передать данные; в нашем случае это будет тег <list:list>, который занимается отображением данных.
Пусть теперь нам необходимо отобразить только одну первую новость:
<fetch using='src/fetcher/NewsFetcher' target='news' first='true'/> <core:datasource id='last_news'> <div class='date'>{$date}</div><div class='title'>{$title}</div> </core:datasource>
Обратите внимание на атрибут тега first, который говорит <fetch> тегу, что нужно передать не весь список данных, а только первый полученный элементв из итератора.
В атрибуте target мы указали идентификатор тега <core:datasource> - это так называемый единичный контейнер данных, в отличие от <list:list> тега. Если вы забудете указать first, тогда шаблонизатор предпримет попытку передать весь итератор (даже если в нем будет всего 1 элемент) в <core:datasource> и будет сгенерировано исключение во время работы шаблона. см. также раздел "Контейнеры данных WACT".
Допустим, нам необходимо вывести все новости отсортировав их по заголовку. Если по-умолчанию новости сортируются по дате, есть способ изменить способ сортировки прямо из шаблона. Для этого можно использовать атрибут order. Это можно сделать так:
<fetch using='src/fetcher/NewsFetcher' target='news' order='title=ASC'/>
[...]
Или так:
<fetch using='src/fetcher/NewsFetcher' target='news'> <fetch:param order='title=ASC'/> </fetch> [...]
Тег <fetch:param> приводит к вызову метода setAttributeName($value) у fetcher-а для каждого своего атрибута. То есть NewsFetcher получит вызов метода setOrder('title=ASC').
Можно указать несколько сортировок, разделяя их запятыми:
<fetch using='src/fetcher/NewsFetcher' target='news'> <fetch:param order='title=ASC,id=DESC'/> </fetch> [...]
Использование order на самом деле приводит к вызову метода sort() для итератора полученного из NewsFetcher, для последнего примера это будет $dataset→sort(array('title' ⇒ 'ASC', 'id' ⇒ 'DESC'));
Иногда перед нами стоит задача вывести только некоторое количество объектов в шаблоне, например, только 3 последние новости. Для этого мы можем использовать атрибуты offset и limit:
<fetch using='src/fetcher/NewsFetcher' target='latest_news' limit='3' order='date=DESC'/>
[...]
Это можно сделать и так:
<fetch using='src/fetcher/NewsFetcher' target='latest_news'> <fetch:param limit='3' order='date=DESC'/> </fetch> [...]
Допустим нам нужно вывести 3 новости, начиная с 3-й:
<fetch using='src/fetcher/NewsFetcher' target='latest_news'> <fetch:param offset='2' limit='3'/> </fetch> [...]
Допустим, у нас есть задача - сделать свой fetcher для выборки объектов класса Node по своим параметрам. Приведем класс этого fetcher-а, который мы назвали NodeKidsFetcher:
<?php lmb_require('limb/web_app/src/fetcher/lmbFetcher.class.php'); lmb_require('limb/active_record/src/lmbActiveRecord.class.php'); lmb_require('limb/dbal/src/criteria/lmbSQLCriteria.class.php'); class NodeKidsFetcher extends lmbFetcher { protected $type; protected $parent_id = 0; protected $path; function setType($type) { $this->type = $type; } function setParentId($parent_id) { if($parent_id) $this->parent_id = $parent_id; } function setParentPath($path) { $this->path = $path; } protected function _createDataSet() { $toolkit = lmbToolkit :: instance(); if($this->path && !$this->parent_id) { if($node = Node :: findByPath('Node', $path)) $this->parent_id = $node->id; } $criteria = new lmbSQLCriteria("parent_id = " . (int)$this->parent_id); if($this->type) { $type_id = NodeType :: generateIdFor($this->type); $criteria->addAnd(new lmbSQLCriteria('type_id ='. $type_id)); } return lmbActiveRecord :: find('Node', $criteria); } } ?>
Обратите внимание, что дочерние классы должны расширять защищенный метод _createDataset(). Это реализовано исходя из того, что родительский класс lmbFetcher содержит функционал по ограничению (offset, limit), по сортировке (order) полученного итератора и этот функционал должен быть всегда доступен клиентам fetcher-ов. Поэтому дочерние классы не перекрывают метод getDataset().
Глядя на методы класса NodeKidsFetcher, можно сделать вывод, что в шаблонах мы можем использовать параметры parent_path, parent_id и type, например:
<fetch using='src/fetcher/NodeKidsFetcher' target='kids'> <fetch:param parent_id='{$#request.id}'> </fetch>
<fetch using='src/fetcher/NodeKidsFetcher' target='kids'> <fetch:param parent_id='{$#request.id}' type='File'> </fetch>
<fetch using='src/fetcher/NodeKidsFetcher' target='kids'> <fetch:param parent_id='{$#request.id}' parent_path='/files'> </fetch>
Атрибут using указывает на класс fetcher-а, при помощи которого будут получены данные.
В последнем примере, если в запросе ничего не придет, будут выбраны дочерние элементы родителя по пути /files.
Тег <active_record:fetch> в основном работает аналогично тегу <fetch>.
Отличия заключаются в следующем:
Подробнее об использовании тега <active_record:fetch> см. в разделе "Использование ACTIVE_RECORD в шаблонах WACT".
Обсуждение