====== Общая схема организация отображения (View). Pull view Vs Push view ======
**View** занимается отображением данных. Подсистема View начиная с релиза 2007.3 вынесена из WEB_APP в отдельный пакет View.
В качестве шаблонизатора в Limb3 по-умолчанию используется [[limb3:ru:packages:wact|шаблонная система WACT]].
Со view связаны 2 понятия:
* **Объект $view**, который является как бы промежуточным звеном между шаблонизатором и остальной частью приложения. Объект $view создается и хранится в тулките.
* **Шаблонизатор**, который получает данные, пославленные во $view и рендерит шаблон, указанный во $view. То, какой шаблонизатор используется зависит от класса объекта $view.
===== Объект $view. Класс lmbView и lmbWactView =====
**$view** - это по сути контейнер с данными, который всегда доступен через toolkit.
**lmbView** - базовый абстрактный класс для реализации $view. **lmbWactView** - наследник от lmbView, в качестве шаблонизатора использует WACT.
То, что по-умолчанию в Limb3 в качестве $view создается экземпляр lmbWactView определяется реализацией метода [[lmb_web_app_tools|lmbWebAppTools]] :: **getView()**. Переопределив этот метод, вы можете поменять шаблонизатор.
lmbView содержит следующие методы:
* **setTemplate($template_name)** - устанавливает имя шаблона
* **render()** - рендерит шаблон. Абстрактный метод, который должен перекрываться в дочерних классах. Результат работы шаблонизатор возвращается в качестве результата этого метода.
* **set($variable_name, $value)** - устанавливает переменную, которая будет передана в корневой контекст шаблона.
* **reset()** - сбрасывает все установленные переменные (но не имя шаблона!)
lmbWactView дополнительно содержит следующиме методы:
* **getWactTemplate()** - возвращает объект класса %%WactTemplate%%
* **setFormDatasource($form_name, $datasource)** - устанавливает источник данных для активного компонента формы в шаблоне.
* **setFormErrors($form_name, $error_list)** - устанавливает список ошибок валидации для активного компонента формы в шаблоне.
* **findChild($id)** - возвращает активный компонент, найденный в WACT шаблон по идентификатору $id
В будущих релизах, возможно, методы setFormDatasource и setFormErrors перейдут в класс lmbView.
===== Рендеринг шаблона =====
Советуем прочитать страницу [[filter_chain|Использование цепочки фильтров для организации Front-Controller]], так как там объясняется, как и где происходит реальный рендеринг шаблона.
Здесь мы немного повторимся и немного уточним: **рендеринг шаблона происходит** в фильтре lmbViewRenderingFilter, но это происходит лишь в том случае, **если $response является пустым**. $response считается пустым, если ни были вызваны следующие методы класса lmbHttpResponse:
* redirect($url)
* readFile($file_path)
* write($file)
* а также если не был установлен статус 304 или 412
Отметим также, что именно в фильтре lmbViewRenderingFilter в шаблон попадают следующие объекты:
* $toolkit
* $request
* $session
Последний факт позволяет использовать в WACT-шаблонах следующие конструкции:
[...]
или
Имя = $name, Логин = $login
[...]
В lmbWebAppTools есть также метод **renderTemplate($template_path)**, который производит рендеринг view "насильно", однако переменные $toolkit, $request и $session в этом случае не передает.
===== PullView vs PushView =====
Существует 2 основных способа передачи данных в шаблоны:
- **push view**, когда шаблон ведет себя пассивно и ждет, когда данные ему придут откуда-нибудь (обычно непосредственно из контроллера или из дополнительной прослойки View-helper-ов).
- **pull view**, когда шаблоны самостоятельно вытягивают данные из модели (базы данных).
В приложениях, построенных на Limb3, возможно использовать оба способа.
По мере накопления практики мы пришли к следующему балансу между push view и pull view:
* Те данные, которые отображаются исходя из текущего действия контроллера желательно передавать во view из контроллера. Если данных имеют иерархический характер (например, заказ и его позиции), тогда мы в контроллере часто удостоверяемся, что "корень" данных (например, заказ) - может быть получен исходя из Запроса, а остальные данные получаются уже в шаблоне. Если же "корень" данных получить не удается, тогда контроллер обычно или выдает страницу с ошибкой или с 404 сообщением (например при помощи метода lmbController :: forwardTo404()), можно также делать redirect на другую страницу.
* Прочие данные (навигация, текущие пользователи, последние события и прочее) - пусть шаблон получает сам.
Такая выработанная схема позволила нам отказаться от иерархии View - классов, когда каждому действию или контроллеру соответствует еще 1 View класс (такая архитектура наблюдается в некоторых фреймворках).
==== push view - передача данных по $view из конструктора ====
push view - это концепция, по которой отображение (View) ведет себя достаточно пассивно по отношению к данным, ожидая, что все данные, которые необходимо будет отобразить, должны придти из внешних источников, в отличие от PullView, когда шаблон может затребовать данные самостоятельно. Обычно передачей данных в шаблон занимается контроллер.
push view в Limb3 обычно используется для передачи данных с форм (ошибки валидации, первоначальные данные) в шаблон, а также в некоторых других, когда использование pull view нецелесообразно.
В lmbController есть следующие средства для передачи данных во $view:
* **Все атрибуты класса**, кроме тех, что начинаются с нижнего подчеркивания, **передаются во $view!**
* **атрибут $view** - чтобы не вызываеть каждый раз lmbToolkit :: instance()->getView();
* **setTemplate($template_path)** - аналог $this->view->setTemplate($template_path);
* **useForm($form_id)** - указывает, что в данный момент этот контроллер будет работать с формой $form_id. Вызывает метод lmbWactView :: setFormErrors($form_id, $this->error_list);
* **setFormDatasource($datasource, $form_id = null)** - Передает в активный компонент формы $form_id источных данных $datasource. Алиас для метода lmbWactView :: setFormDatasource($form_name, $datasource). Если ранее был вызо useForm($form_id), то в $form_id для вызова setFormDatasource() можно уже опустить.
* **resetView()** - аналог вызова $this->view->reset()
* **passToView($var, $value)** - аналог вызова $this->view->set($var, $value).
Пример, кода использующего концепцию push view:
class FeedbackController extends lmbController
{
function doSend()
{
$this->setTemplate('feedback/send_result.html');
if($this->_sendMail())
{
$this->resetView();
$this->view->set('success_send', 1);
// или просто $this->success_send = 1;
// или $this->passToView('success_send', 1);
}
else
$this->view->set('error_send', 1);
}
protected function sendMail(){[...]}
}
==== pull view - получение данных прямо в шаблоне ====
pull view предусматривает, что шаблон вытянет данные самостоятельно. Самый простой способ - это использование php-вставок, в которых вызываются нужные методы для получения данных, а затем вывод этих данных при помощи более "классических" средств шаблонизатора. см. [[limb3:ru:packages:wact:php_code_in_templates|Использование php-кода в WACT-шаблонах]].
В WACT существует такое понятие как fetcher-ы и специальные теги. Fetcher-ы исторически использовались нами для реализации pull-подхода, пока WACT не был научен нормально понимать php-вставки и php-переменные. Рекомендуем почитать:
* [[limb3:ru:packages:active_record:in_wact_templates|Использование fetch и active_record:fetch тегов-ов в WACT-шаблонах]]
* [[limb3:ru:packages:wact:fetch_tags|Использование ACTIVE_RECORD в шаблонах WACT]]
Правда, в конце концов, мы пришли к пониманию того, что теги - несколько ограниченное решение. Возможно, что ситуация с fetcher-ами изменится к релизу 2007.4