<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.controller.plugins" xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Плагины</title>

    <sect2 id="zend.controller.plugins.introduction">
        <title>Введение</title>

        <para>
            Архитектура контроллеров включает в себя систему плагинов, которая
            позволяет добавлять свой код, который будет вызываться при
            определенных событиях в процессе жизни контроллера. Фронт-контроллер
            использует брокер плагинов (plugin broker) в качестве реестра
            пользовательских плагинов, брокер плагинов также обеспечивает вызов
            методов событий в каждом плагине, зарегистрированном через
            фронт-контроллер.
        </para>

        <para>
            Методы событий определены в абстрактном классе
            <classname>Zend_Controller_Plugin_Abstract</classname>, от которого должны
            наследовать все пользовательские плагины:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <code>routeStartup()</code> вызывается до того, как
                    <classname>Zend_Controller_Front</classname> вызовет
                    <link linkend="zend.controller.router">маршрутизатор</link>
                    для сопоставления запроса с зарегистрированными маршрутами.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>routeShutdown()</code> вызывается после того, как
                    <link linkend="zend.controller.router">маршрутизатор</link>
                    завершит обработку запроса.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>dispatchLoopStartup()</code> вызывается до того,
                    как <classname>Zend_Controller_Front</classname> войдет в цикл
                    диспетчеризации.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>preDispatch()</code> вызывается до того, как
                    <link linkend="zend.controller.dispatcher">диспетчером</link>
                    будет вызвано действие. Этот обратный
                    вызов (callback) позволяет реализовать поведение посредника
                    или фильтра. Через изменение запроса и сброс его
                    флага диспетчеризации (методом
                    <code>Zend_Controller_Request_Abstract::setDispatched(false)</code>)
                    текущее действие может быть пропущено и/или заменено на
                    другое.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>postDispatch()</code> вызывается после того, как
                    действие было вызвано
                    <link linkend="zend.controller.dispatcher">диспетчером</link>.
                    Этот обратный вызов позволяет реализовать поведение фильтра
                    или посредника. Через изменение запроса и сброс его
                    флага диспетчеризации (методом
                    <code>Zend_Controller_Request_Abstract::setDispatched(false)</code>)
                    может быть определено новое действие для
                    диспетчеризации.
                </para>
            </listitem>

            <listitem>
                <para>
                    <code>dispatchLoopShutdown()</code> вызывается после выхода
                    <classname>Zend_Controller_Front</classname> из его цикла
                    диспетчеризации.
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.plugins.writing">
        <title>Написание плагинов</title>

        <para>
            Для того, чтобы написать класс плагина, просто включите и расширьте
            абстрактный класс <classname>Zend_Controller_Plugin_Abstract</classname>:
        </para>

        <programlisting language="php"><![CDATA[
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
    // ...
}
]]></programlisting>

        <para>
            Ни один из методов класса
            <classname>Zend_Controller_Plugin_Abstract</classname> не является
            абстрактным, поэтому классы плагинов не обязательно должны
            реализовывать все из перечисленных выше методов событий.
            Разработчики плагинов могут реализовывать только те методы, которые
            требуются для их конкретных нужд.
        </para>

        <para>
            <classname>Zend_Controller_Plugin_Abstract</classname> также делает объекты
            запроса и ответа доступными плагинам контроллеров через методы
            <code>getRequest()</code> и <code>getResponse()</code>,
            соответственно.
        </para>
    </sect2>

    <sect2 id="zend.controller.plugins.using">
        <title>Использование плагинов</title>

        <para>
            Классы плагинов регистрируются через
            <code>Zend_Controller_Front::registerPlugin()</code>, их можно
            регистрировать в любой момент времени. Следующий пример
            демонстрирует использование плагина в цепочке контроллеров:
        </para>

        <programlisting language="php"><![CDATA[
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
    public function routeStartup(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()
             ->appendBody("<p>routeStartup() called</p>\n");
    }

    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()
             ->appendBody("<p>routeShutdown() called</p>\n");
    }

    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()
             ->appendBody("<p>dispatchLoopStartup() called</p>\n");
    }

    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()
             ->appendBody("<p>preDispatch() called</p>\n");
    }

    public function postDispatch(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()
             ->appendBody("<p>postDispatch() called</p>\n");
    }

    public function dispatchLoopShutdown()
    {
        $this->getResponse()
             ->appendBody("<p>dispatchLoopShutdown() called</p>\n");
    }
}

$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('/path/to/controllers')
      ->setRouter(new Zend_Controller_Router_Rewrite())
      ->registerPlugin(new MyPlugin());
$front->dispatch();
]]></programlisting>

        <para>
            При условии, что вызываемые действия не производят вывод, и
            что вызвано только одно действие, с плагином выше должен получиться
            следующий вывод:
        </para>

        <programlisting language="php"><![CDATA[
<p>routeStartup() called</p>
<p>routeShutdown() called</p>
<p>dispatchLoopStartup() called</p>
<p>preDispatch() called</p>
<p>postDispatch() called</p>
<p>dispatchLoopShutdown() called</p>
]]></programlisting>

        <note>
            <para>
                Плагины могут регистрироваться в любой точке выполнения
                фронт-контроллера. Однако, если событие, для которого
                плагин имеет зарегистрированный метод события, уже произошло, то
                этот метод не будет запущен.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.controller.plugins.manipulating">
        <title>Извлечение и работа с плагинами</title>

        <para>
            Иногда может понадобиться отменить регистрацию плагина или извлечь
            его. Следующие методы фронт-контроллера позволяют сделать это:
        </para>

        <itemizedlist>
            <listitem><para>
                <code>getPlugin($class)</code> позволяет извлекать плагин по
                имени класса. Если не найден соответствующий плагин, то
                возвращается false. Если зарегистрировано более одного плагина
                этого класса, то будет возвращен массив.
            </para></listitem>

            <listitem><para>
                <code>getPlugins()</code> возвращает весь стек плагинов.
            </para></listitem>

            <listitem><para>
                <code>unregisterPlugin($plugin)</code> производит удаление
                плагина из стека. Вы можете передавать объект плагина или имя
                класса плагина, регистрацию которого вы хотите отменить. Если вы
                передаете имя класса, то будут удалены все плагины этого класса.
            </para></listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.plugins.standard">
        <title>Плагины, включенные в стандартную поставку</title>

        <para>
            Zend Framework в его стандартной поставке включает в себя плагин для
            обработки ошибок.
        </para>

        <xi:include href="Zend_Controller-Plugins-ActionStack.xml" />
        <xi:include href="Zend_Controller-Plugins-ErrorHandler.xml" />
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
