Получение сконфигурированного MVC-приложения, готового к обработке запроса, требует наличия дополнительного кода, объем которого зависит от используемого функционала: установка соединения с базой данных, конфигурирование видов и их помощников, конфигурирование макетов (layouts), регистрация плагинов, регистрация помощников действий и так далее.
Кроме того, вы можете захотеть повторно использовать один и тот же код для загрузки тестов, сервисных скриптов, скриптов, предназначенных для запуска через крон. Можно просто добавлять свой скрипт загрузки, но часто встречаются инициализации, зависящие от окружения - например, для запуска через крон MVC может быть лишним, а для сервисного скрипта может быть достаточно только слоя баз данных.
Zend_Application
облегчает управление начальной
загрузкой и способствует повторному использованию путем инкапсуляции
загрузки в соответствии с парадигмой ООП.
Zend_Application
состоит из трех областей:
Zend_Application
: загружает окружение
PHP, включая include_paths и автозагрузку
(autoloading), инстанцирует запрошенный загрузочный класс.
Zend_Application_Bootstrap
: предоставляет
интерфейсы для загрузочных классов.
Zend_Application_Bootstrap_Bootstrap
предоставляет общий функционал, удовлетворяющий большинство
нужд по начальной загрузке, включающие в себя алгоритмы проверки
зависимостей и возможность загрузки ресурсов по требованию.
Zend_Application_Resource
предоставляет
интерфейс для стандартных ресурсов загрузки,
которые могут быть загружены по требованию через экземпляр
загрузочного класса, и несколько реализаций ресурсов,
используемых по умолчанию.
Разработчики могут создавать загрузочный класс для приложения,
расширяя Zend_Application_Bootstrap_Bootstrap
или, как минимум, реализуя интерфейс
Zend_Application_Bootstrap_Bootstrapper
.
Входная точка (например, public/index.php
)
будет загружать Zend_Application
и
инстанцировать его путем передачи:
Текущего окружения
Опций для загрузки
Опции загрузки включают в себя путь к файлу, содержащему в себе загрузочный класс и, опционально:
Любые дополнительные пути для добавления в include_path
Любые дополнительные пространства имен автозагрузки, которые требуется зарегистрировать
Любые установки php.ini
для инициализации
Имя класса загрузки (если используется имя, отличное от "Bootstrap")
Пары префикс-путь для ресурсов
Любые ресурсы для использования (указываются через имя класса или их короткое имя)
Дополнительный путь к загружаемому конфигурационному файлу
Дополнительные опции конфигурации
Опции могут быть массивом, объектом Zend_Config
или путью к конфигурационному файлу.
Второй областью отвественности компоненты
Zend_Application
является
выполнение загрузки приложения. Загрузочные классы
должны как минимум реализовывать интерфейс
Zend_Application_Bootstrap_Bootstrapper
,
который определяет следующий API:
interface Zend_Application_Bootstrap_Bootstrapper { public function __construct($application); public function setOptions(array $options); public function getApplication(); public function getEnvironment(); public function getClassResources(); public function getClassResourceNames(); public function bootstrap($resource = null); public function run(); }
Этот API позволяет классу загрузки принимать окружение и конфигурацию из объекта приложения, определять ресурсы, за загрузку которых он отвечает, выполнять загрузку и запуск приложения.
Вы можете сами реализовывать этот интерфейс, расширять
Zend_Application_Bootstrap_BootstrapAbstract
или использовать
Zend_Application_Bootstrap_Bootstrap
.
Кроме этого функционала есть и другие требующие внимания области, с которыми вы должны ознакомиться.
Zend_Application_Bootstrap_BootstrapAbstract
предоставляет простое соглашение для определения
методов ресурсов. Любой защищенный метод с именем,
начинающимся с _init, будет считаться
методом ресурса.
Для того, чтобы запустить один метод ресурса, вызывайте
метод bootstrap()
с именем ресурса в
качестве аргумента. Именем ресурса будет имя метода без префикса
_init.
Для того, чтобы запустить несколько методов ресурсов, передавайте массив имен. А для того, чтобы запустить все методы ресурсов, вызывайте метод без аргументов.
Возьмем следующий загрузочный класс:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initFoo() { // ... } protected function _initBar() { // ... } protected function _initBaz() { // ... } }
Для того, чтобы запустить только метод
_initFoo()
, сделайте следующее:
$bootstrap->bootstrap('foo');
Для того, чтобы запустить методы
_initFoo()
и
_initBar()
, сделайте следующее:
$bootstrap->bootstrap(array('foo', 'bar'));
Для того, чтобы запустить все методы ресурсов,
используйте bootstrap()
без аргументов:
$bootstrap->bootstrap();
Для того, чтобы вы могли сделать свои загрузки более пригодными для повторного использования, мы реализовали возможность помещать свои ресурсы в классы-плагины ресурсов. Это позволит вам легко комбинировать ресурсы, используя конфигурацию. Ниже будет описание того, как создавать ресурсы, в данном разделе мы только покажем, как использовать их.
Если ваша загрузка должна поддерживать
плагины ресурсов, то вам нужно реализовать дополнительный
интерфейс
Zend_Application_Bootstrap_ResourceBootstrapper
.
Этот интерфейс определяет API для
определения местонахождения, регистрации и загрузки плагинов
ресурсов:
interface Zend_Application_Bootstrap_ResourceBootstrapper { public function registerPluginResource($resource, $options = null); public function unregisterPluginResource($resource); public function hasPluginResource($resource); public function getPluginResource($resource); public function getPluginResources(); public function getPluginResourceNames(); public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader); public function getPluginLoader(); }
Плагины ресурсов в основном дают возможность создавать инициализаторы ресурсов, которые могут повторно использоваться в различных приложениях. Это позволит вам поддерживать порядок в вашей действующей загрузке и внедрять новые ресурсы без необходимости внесения изменений в собственно загрузке.
Zend_Application_Bootstrap_BootstrapAbstract
(и, следовательно, наследующий от него класс
Zend_Application_Bootstrap_Bootstrap
)
реализуют этот интерфейс, позволяя вам использовать
плагины ресурсов.
Для того, чтобы использовать плагины ресурсов, вы должны
указывать их в опциях, передаваемых объектам приложения и/или
загрузки. Эти опции могут указываться через конфигурационный
файл или передаваться вручную.
Опции будут массивом пар ключ/опции, где ключом является
имя ресурса. Именем ресурса будет часть строки, следующая
после префикса класса. Например,
ресурсы, поставляемые c Zend Framework'ом, имеют префикс класса
"Zend_Application_Resource_
", все, что
следует за ним, будет именем ресурса. Например:
$application = new Zend_Application(APPLICATION_ENV, array( 'resources' => array( 'FrontController' => array( 'controllerDirectory' => APPLICATION_PATH . '/controllers', ), ), ));
Это означает, что должен использоваться ресурс "FrontController" с указанными опциями.
Если вы планируете писать собственные плагины ресурсов
либо добавить сторонние, то нужно будет указать вашей
загрузке, где их искать.
Внутри себя загрузка использует
Zend_Loader_PluginLoader
, поэтому
достаточно указать префикс класса и путь к директории с
плагинами ресурсов.
Для примера предположим, что вы имеете свои плагины ресурсов
в директории APPLICATION_PATH/resources/
,
и они используют общий префикс
My_Resource
.
Вы можете передать эту информацию объекту приложения так,
как показано ниже:
$application = new Zend_Application(APPLICATION_ENV, array( 'pluginPaths' => array( 'My_Resource' => APPLICATION_PATH . '/resources/', ), 'resources' => array( 'FrontController' => array( 'controllerDirectory' => APPLICATION_PATH . '/controllers', ), ), ));
После этого вы можете использовать ресурсы из этой директории.
Так же, как и в случае с методами ресурсов, вы используете
метод bootstrap()
для выполнения
плагинов ресурсов.
И точно так же вы можете указывать один плагин ресурса,
несколько плагинов ресурсов (через массив), либо запускать все плагины
сразу. Кроме того, вы можете комбинировать их с методами
ресурсов.
// Выполнить один: $bootstrap->bootstrap('FrontController'); // Выполнить несколько: $bootstrap->bootstrap(array('FrontController', 'Foo')); // Выполнить все ресурсы и плагины: $bootstrap->bootstrap();
Большинство, если не все, методы и плагины ресурсов будут инициализировать объекты, и во многих случаях эти объекты будут нужны где-то еще в приложении. Как получить к ним доступ?
Zend_Application_Bootstrap_BootstrapAbstract
предоставляет локальный реестр для этих объектов.
Для того, чтобы сохранять свои объекты в нем, просто возвращайте
их из своего ресурса.
Для большей гибкости этот реестр внутри себя ссылается на
"контейнеры";
единственное требование состоит в том, чтобы это был объект.
Ресурсы регистрируются как свойства, имена которых совпадают
с именами ресурсов.
По умолчанию используется экземпляр
Zend_Registry
, но вы можете при
желании указывать любой другой объект.
Для работы с контейнерами могут использоваться методы
setContainer()
и
getContainer()
.
Метод getResource($resource)
может использоваться для извлечения ресурса из контейнера,
а hasResource($resource)
- для
проверки того, был ли зарегистрирован данный ресурс.
Для примера рассмотрим базовый ресурс вида:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initView() { $view = new Zend_View(); // дальнейшая инициализация... return $view; } }
Вы можете затем проверять его наличие и/или извлекать его как показано ниже:
// Использование пары has/getResource() if ($bootstrap->hasResource('view')) { $view = $bootstrap->getResource('view'); } // Через контейнер: $container = $bootstrap->getContainer(); if (isset($container->view)) { $view = $container->view; }
Следует заметить, что реестр и контейнер не являются
глобальными. Это означает, что вам нужно иметь доступ к объекту
загрузки с тем, чтобы можно было извлекать ресурсы.
Zend_Application_Bootstrap_Bootstrap
предоставляет некоторые удобства для этого:
во время выполнения run()
он
регистрирует себя в качестве параметра "bootstrap"
во фронт-контроллере, это позволяет извлекать его внутри
маршрутизатора, диспетчера, плагинов и контроллеров действий.
Например, если вы хотите внутри своего контроллера действий получить доступ к ресурсу вида из примеров выше, то можете сделать следующее:
class FooController extends Zend_Controller_Action { public function init() { $bootstrap = $this->getInvokeArg('bootstrap'); $view = $bootstrap->getResource('view'); // ... } }
Кроме выполнения методов и плагинов ресурсов, необходимо также гарантировать, что они выполняются один и только один раз. Они предназначены для загрузки приложения, и выполнение их больше одного раза может привести к непроизводительному расходованию ресурсов.
В то же время некоторые ресурсы могут зависеть от других и
требовать их предварительной загрузки до начала своего
выполнения.
Для решения этих двух проблем
Zend_Application_Bootstrap_BootstrapAbstract
предоставляет простой и эффективный механизм для отслеживания
зависимостей.
Как было сказано ранее, все ресурсы - как методы, так и
плагины, - загружаются путем вызова
bootstrap($resource)
, где
$resource
является именем ресурса или
массивом ресурсов. Если параметр $resource
опущен, то это означает, что все ресурсы должны быть запущены.
Если ресурс зависит от других ресурсов, то он должен вызывать
метод bootstrap()
в своем коде
для обеспечения выполнения этих ресурсов.
Последующие вызовы для этих ресурсов будут проигнорированы.
В методе ресурса такой вызов будет выглядеть следующим образом:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initRequest() { // Обеспечение инициализации контроллера $this->bootstrap('FrontController'); // Извлечение фронт-контроллера из реестра загрузки $front = $this->getResource('FrontController'); $request = new Zend_Controller_Request_Http(); $request->setBaseUrl('/foo'); $front->setRequest($request); // Обеспечение сохранения запроса в реестре загрузки return $request; } }
Как было сказано ранее, хорошим способом создания повторно используемых ресурсов загрузки и выделения кода в отдельные классы является использование плагинов ресурсов. Хотя Zend Framework поставляется с набором стандартных плагинов ресурсов, замысел состоит в том, что разработчики должны писать собственные плагины с целью инкапсуляции собственного кода, предназначенного для инициализации.
Ресурсы должны только реализовывать интерфейс
Zend_Application_Resource_Resource
или, что
является более простым вариантом, расширять абстрактный класс
Zend_Application_Resource_ResourceAbstract
.
Базовый интерфейс довольно прост:
interface Zend_Application_Resource_Resource { public function __construct($options = null); public function setBootstrap( Zend_Application_Bootstrap_Bootstrapper $bootstrap ); public function getBootstrap(); public function setOptions(array $options); public function getOptions(); public function init(); }
Он определяет только, что ресурс должен принимать опции через конструктор, иметь механизмы для установки/получения опций, механизмы для установки/получения объекта загрузочного класса и метод инициализации.
Для примера предположим, что вы имеете инициализацию вида, одинаковую для нескольких ваших приложений. Вы используете в них одну и ту же декларацию DOCTYPE, одни и те же CSS-стили, скрипты JavaScript, а также хотите иметь возможность задавать базовый заголовок документа через конфигурацию. Ресурс, выполняющий такую инициализацию, может выглядеть следующим образом:
class My_Resource_View extends Zend_Application_Resource_ResourceAbstract { protected $_view; public function init() { // Возвращает вид, таким образом, он будет сохранен в реестре return $this->getView(); } public function getView() { if (null === $this->_view) { $options = $this->getOptions(); $title = ''; if (array_key_exists('title', $options)) { $title = $options['title']; unset($options['title']); } $view = new Zend_View($options); $view->doctype('XHTML1_STRICT'); $view->headTitle($title); $view->headLink()->appendStylesheet('/css/site.css'); $view->headScript()->appendfile('/js/analytics.js'); $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper( 'ViewRenderer' ); $viewRenderer->setView($view); $this->_view = $view; } return $this->_view; } }
Зарегистрировав путь к этому плагину ресурса, вы можете использовать его в своем приложении. Сверх того, благодаря использованию загрузчика плагинов вы эффективно переопределите идущий в поставке плагин ресурса "View", тем самым обеспечивая использование своего плагина вместо него.