# Плагины

## Введение

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

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

- `routeStartup()` вызывается до того, как `Zend_Controller_Front` вызовет маршрутизатор для сопоставления запроса с зарегистрированными маршрутами.

- `routeShutdown()` вызывается после того, как маршрутизатор завершит обработку запроса.

- `dispatchLoopStartup()` вызывается до того, как `Zend_Controller_Front` войдет в цикл диспетчеризации.

- `preDispatch()` вызывается до того, как диспетчером будет вызвано действие. Этот обратный вызов (callback) позволяет реализовать поведение посредника или фильтра. Через изменение запроса и сброс его флага диспетчеризации (методом `Zend_Controller_Request_Abstract::setDispatched(false)`) текущее действие может быть пропущено и/или заменено на другое.

- `postDispatch()` вызывается после того, как действие было вызвано диспетчером. Этот обратный вызов позволяет реализовать поведение фильтра или посредника. Через изменение запроса и сброс его флага диспетчеризации (методом `Zend_Controller_Request_Abstract::setDispatched(false)`) может быть определено новое действие для диспетчеризации.

- `dispatchLoopShutdown()` вызывается после выхода `Zend_Controller_Front` из его цикла диспетчеризации.

## Написание плагинов

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

    class MyPlugin extends Zend_Controller_Plugin_Abstract
    {
        // ...
    }

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

`Zend_Controller_Plugin_Abstract` также делает объекты запроса и ответа доступными плагинам контроллеров через методы `getRequest()` и `getResponse()`, соответственно.

## Использование плагинов

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

    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();

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

    <p>routeStartup() called</p>
    <p>routeShutdown() called</p>
    <p>dispatchLoopStartup() called</p>
    <p>preDispatch() called</p>
    <p>postDispatch() called</p>
    <p>dispatchLoopShutdown() called</p>

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

## Извлечение и работа с плагинами

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

- `getPlugin($class)` позволяет извлекать плагин по имени класса. Если не найден соответствующий плагин, то возвращается false. Если зарегистрировано более одного плагина этого класса, то будет возвращен массив.

- `getPlugins()` возвращает весь стек плагинов.

- `unregisterPlugin($plugin)` производит удаление плагина из стека. Вы можете передавать объект плагина или имя класса плагина, регистрацию которого вы хотите отменить. Если вы передаете имя класса, то будут удалены все плагины этого класса.

## Плагины, включенные в стандартную поставку

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