7.3. Фронт-контроллер

7.3.1. Обзор

Zend_Controller_Front реализует паттерн Front Controller, используемый в приложениях MVC. Его назначение состоит в инициализации окружения запроса, проложении маршрута приходящего запроса и последующем запуске выявленных действий. Он агрегирует все ответы и возвращает их по завершении процесса.

Zend_Controller_Front также реализует паттерн Singleton, это означает, что в любое время может быть доступен только один экземпляр этого класса. Это позволяет ему также выступать в качестве реестра, в котором хранятся другие объекты, участвующие в процессе диспетчеризации.

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

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

[Замечание] Поведение по умолчанию

По умолчанию фронт-контроллер загружает плагин ErrorHandler и помощник действий ViewRenderer. Это сделано для упрощения обработки ошибок и рендеринга видов в контроллерах, соответственно.

Для того, чтобы отключить ErrorHandler, произведите следующее до вызова метода dispatch():

<?php
// Отключение плагина ErrorHandler:
$front->setParam('noErrorHandler', true);
            

Для того, чтобы отключить ViewRenderer, сделайте следующее до вызова метода dispatch():

<?php
// Отключение помощника ViewRenderer:
$front->setParam('noViewRenderer', true);
            

7.3.2. Ключевые методы

Фронт-контроллер имеет несколько аксессоров для настройки его конфигурации. Тем не менее, он имеет несколько ключевых в его функционале методов.

7.3.2.1. getInstance()

getInstance() используется для получения экземпляра фронт-контроллера. Поскольку фронт-контроллер реализует паттерн Singleton, то это также единственно доступный способ инстанцирования объекта фронт-контроллера.

<?php
$front = Zend_Controller_Front::getInstance();
            

7.3.2.2. setControllerDirectory() и addControllerDirectory()

setControllerDirectory() используется для того, чтобы указать диспетчеру, где искать файлы классов контроллеров действий. Он принимает один путь или ассоциативный массив пар модуль => путь в качестве параметра.

Примеры:

// Установка директории контроллеров, используемой по умолчанию:
$front->setControllerDirectory('../application/controllers');

// Одновременная установка нескольких директорий модулей:
$front->setControllerDirectory(array(
    'default' => '../application/controllers',
    'blog'    => '../modules/blog/controllers',
    'news'    => '../modules/news/controllers',
));

// Добавление директории модуля 'foo':
$front->addControllerDirectory('../modules/foo/controllers', 'foo');
            
[Замечание] Замечание

Если вы используете addControllerDirectory() без имени модуля, то он установит директорию для модуля default. Если директория уже существует, то она будет перезаписана.

Можно получить текущие установки для директорий контроллеров, используя метод getControllerDirectory(). Он вернет массив пар модуль => директория.

7.3.2.3. dispatch()

dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) является "рабочей лошадкой" фронт-контроллера. Он может опционально принимать объект запроса и/или объект ответа, что дает разработчикам возможность передавать свои объекты.

Если методу dispatch() не были переданы объект запроса или ответа, то он будет проверять, были ли ранее зарегистрированы объекты, и использовать их, либо инстанцировать версии по умолчанию (в обоих случаях по умолчанию будут использоваться разновидность HTTP).

Аналогичным образом dispatch() производит проверку на уже зарегистрированные объекты маршрутизатора и диспетчера, и если они не найдены, то инстанцирует версии по умолчанию.

Процесс диспетчеризации имеет три отдельных события:

  • Маршрутизация

  • Диспетчеризация

  • Ответ

Маршрутизация производится только один раз, когда вызывается dispatch(), при этом используются значения в объекте запроса. Диспетчеризация производится циклически. Запрос может означать вызов нескольких действий, контроллер или плагин могут сбрасывать объект запроса для дополнительного вызова других действий. Когда все действия выполнены, фронт-контроллер возвращает ответ.

7.3.2.4. run()

Zend_Controller_Front::run($path) - статический метод, принимающий только путь к директории контроллеров. Он извлекает экземпляр фронт-контроллера через getInstance()), регистрирует этот путь через setControllerDirectory(), и в конце вызывает метод dispatch().

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

<?php
// Инстанцирование фронт-контроллера, установка директории контроллера и
// выполнение диспетчеризации одной строкой:
Zend_Controller_Front::run('../application/controllers');
            

7.3.3. Методы-аксессоры для конфигурирования

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

  • resetInstance() может использоваться для сброса всех текущих настроек. Он в основном предназначен для тестирования, но может также использоваться в тех случаях, когда нужно связать между собой несколько фронт-контроллеров.

  • (set|get)DefaultControllerName() позволяют установить другое имя используемого по умолчанию контроллера (иначе используется 'index') и получить текущее значение. Они служат посредниками к диспетчеру.

  • (set|get)DefaultActionName() позволяют установить другое имя используемого по умолчанию действия (иначе используется 'index') и получить текущее значение. Они служат посредниками к диспетчеру.

  • (set|get)Request() позволяют установить класс запроса или его объект для использования в процессе диспетчеризации и получить текущий объект. При установке объекта запроса вы можете передать имя класса запроса, в этом случае метод загрузит файл класса и инстанцирует его.

  • (set|get)Router() позволяют установить класс маршрутизатора или его объект, используемые в течение процесса диспетчеризации, и получить текущий объект. Когда устанавливается объект маршрутизатора, вы можете передать имя класса маршрутизатора, в этом случае метод загрузит файл класса и инстанцирует его.

    При извлечении объекта маршрутизатора сначала производится проверка, представлен ли во фронт-контроллере такой объект и в случае его отсутствия инстанцирует испольуемый по умолчанию маршрутизатор (Rewrite Router).

  • (set|get)BaseUrl() дают возможность установить базовый URL, который удаляется из начала при маршрутизации запросов, и получить его текущее значение. Это значение передается объекту запроса непосредственно до маршрутизации.

  • (set|get)Dispatcher() дают возможность установки класса диспетчера или его объекта для использования в течение диспетчеризации, и получения текущего объекта. При установке объекта диспетчера можно передать имя класса диспетчера, в этом случае метод загрузит файл класса и инстанцирует его.

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

  • (set|get)Response() дают возможность установить класс ответа или его объект для использования в процессе диспетчеризации, и извлечь текущий объект. При установке объекта ответа можно передать имя класса ответа, в этом случае метод загрузит файл класса и инстанцирует его.

  • registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null) позволяет регистрировать объекты плагинов. Путем установки опционального параметра $stackIndex, вы можете контролировать порядок, в котором выполняются плагины.

  • unregisterPlugin($plugin) позволяет отменять регистрацию объектов плагинов. $plugin может быть как объектом плагина, так и строкой, обозначающей класс плагина, регистрацию которого надо отменить.

  • throwExceptions($flag) используется для включения/отключения возможности генерации исключений в течение процесса диспетчеризации. По умолчанию исключения отлавливаются и размещаются в объекте ответа; включение throwExceptions() переопределит это поведение

    Более полробную информацию читайте в Раздел 7.12, «Исключения».

  • returnResponse($flag) используется для того, чтобы указать фронт-контроллеру - возвращать ли ответ из dispatch() (true), либо ответ должен быть отправлен автоматически (false). По умолчанию ответ отправляется автоматически (через вызов Zend_Controller_Response_Abstract::sendResponse()); включение returnResponse() переопределит это поведение.

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

7.3.4. Параметры фронт-контроллера

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

  • setParam($name, $value) дает возможность установить единственный параметр с именем $name и значением $value.

  • setParams(array $params) позволяет установить несколько параметров одновременно с помощью ассоциативного массива.

  • getParam($name) дает возможность извлечь один параметр за один раз, используя его имя $name в качестве идентификатора.

  • getParams() позволяет извлечь все параметры за один раз.

  • clearParams() позволяет удалить один параметр (путем передачи строкового идентификатора), нескольких параметров (путем передачи массива строковых идентификаторов) или весь стек параметров (без передачи чего-либо).

Есть несколько предопределенных параметров специально для использования в цепочке диспетчеризации:

  • useDefaultControllerAlways используется для указания диспетчеру, что следует использовать контроллер по умолчанию в модуле по умолчанию для любых запросов, диспетчеризация которых невозможна (т.е. модуль, контроллер и/или действие не существуют). По умолчанию он отключен.

    См. Раздел 7.12.3, «Исключения в MVC, с которыми вы можете встретиться» за более подробной информацией об использовании этого параметра настройки.

  • disableOutputBuffering используется для указания диспетчеру, что не следует использовать буферизацию вывода для сбора данных на вывод, генерируемых контроллерами действий. По умолчанию диспетчер собирает весь вывод и присоединяет его к телу содержимого в объекте ответа.

  • noViewRenderer используется для отключения помощника ViewRenderer. Установите этот параметр в true для его отключения.

  • noErrorHandler используется для отключения плагина Error Handler Установите этот параметр в true для его отключения.

7.3.5. Создание подклассов фронт-контроллера

При создании подкласса фронт-контроллера, необходимо, как минимум, переопределить метод getInstance().

 class My_Controller_Front extends Zend_Controller_Front
{
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

        

Такое переопределение метода getInstance() гарантирует то, что последующий вызов Zend_Controller_Front::getInstance() вернет экземпляр созданного вами подкласса вместо экземпляра Zend_Controller_Front - это особенно полезно для некоторых альтернативных маршрутизаторов и помощников видов.

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

    Поддержать сайт на родительском проекте КГБ