Теоретические основы работы с Zend_Application
Получение сконфигурированного 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:
Этот API позволяет классу загрузки принимать окружение
и конфигурацию из объекта приложения, определять ресурсы,
за загрузку которых он отвечает, выполнять загрузку и запуск
приложения.
Вы можете сами реализовывать этот интерфейс, расширять
Zend_Application_Bootstrap_BootstrapAbstract
или использовать
Zend_Application_Bootstrap_Bootstrap.
Кроме этого функционала есть и другие требующие внимания области,
с которыми вы должны ознакомиться.
Методы ресурсовZend_Application_Bootstrap_BootstrapAbstract
предоставляет простое соглашение для определения
методов ресурсов. Любой защищенный метод с именем,
начинающимся с _init, будет считаться
методом ресурса.
Для того, чтобы запустить один метод ресурса, вызывайте
метод bootstrap() с именем ресурса в
качестве аргумента. Именем ресурса будет имя метода без префикса
_init.
Для того, чтобы запустить несколько методов ресурсов,
передавайте массив имен. А для того, чтобы запустить
все методы ресурсов, вызывайте метод без аргументов.
Возьмем следующий загрузочный класс:
Для того, чтобы запустить только метод
_initFoo(), сделайте следующее:
bootstrap('foo');
]]>
Для того, чтобы запустить методы
_initFoo() и
_initBar(), сделайте следующее:
bootstrap(array('foo', 'bar'));
]]>
Для того, чтобы запустить все методы ресурсов,
используйте bootstrap() без аргументов:
bootstrap();
]]>Загрузки, использующие плагины ресурсов
Для того, чтобы вы могли сделать свои загрузки более пригодными
для повторного использования, мы реализовали возможность
помещать свои ресурсы в классы-плагины ресурсов.
Это позволит вам легко комбинировать ресурсы, используя
конфигурацию.
Ниже будет описание того, как
создавать ресурсы, в данном разделе мы только
покажем, как использовать их.
Если ваша загрузка должна поддерживать
плагины ресурсов, то вам нужно реализовать дополнительный
интерфейс
Zend_Application_Bootstrap_ResourceBootstrapper.
Этот интерфейс определяет API для
определения местонахождения, регистрации и загрузки плагинов
ресурсов:
Плагины ресурсов в основном дают возможность
создавать инициализаторы ресурсов, которые могут повторно
использоваться в различных приложениях.
Это позволит вам поддерживать порядок в вашей действующей
загрузке и внедрять новые ресурсы без
необходимости внесения изменений в собственно загрузке.
Zend_Application_Bootstrap_BootstrapAbstract
(и, следовательно, наследующий от него класс
Zend_Application_Bootstrap_Bootstrap)
реализуют этот интерфейс, позволяя вам использовать
плагины ресурсов.
Для того, чтобы использовать плагины ресурсов, вы должны
указывать их в опциях, передаваемых объектам приложения и/или
загрузки. Эти опции могут указываться через конфигурационный
файл или передаваться вручную.
Опции будут массивом пар ключ/опции, где ключом является
имя ресурса. Именем ресурса будет часть строки, следующая
после префикса класса. Например,
ресурсы, поставляемые c Zend Framework'ом, имеют префикс класса
"Zend_Application_Resource_", все, что
следует за ним, будет именем ресурса. Например:
array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));
]]>
Это означает, что должен использоваться ресурс
"FrontController" с указанными опциями.
Если вы планируете писать собственные плагины ресурсов
либо добавить сторонние, то нужно будет указать вашей
загрузке, где их искать.
Внутри себя загрузка использует
Zend_Loader_PluginLoader, поэтому
достаточно указать префикс класса и путь к директории с
плагинами ресурсов.
Для примера предположим, что вы имеете свои плагины ресурсов
в директории APPLICATION_PATH/resources/,
и они используют общий префикс
My_Resource.
Вы можете передать эту информацию объекту приложения так,
как показано ниже:
array(
'My_Resource' => APPLICATION_PATH . '/resources/',
),
'resources' => array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));
]]>
После этого вы можете использовать ресурсы из этой директории.
Так же, как и в случае с методами ресурсов, вы используете
метод bootstrap() для выполнения
плагинов ресурсов.
И точно так же вы можете указывать один плагин ресурса,
несколько плагинов ресурсов (через массив), либо запускать все плагины
сразу. Кроме того, вы можете комбинировать их с методами
ресурсов.
bootstrap('FrontController');
// Выполнить несколько:
$bootstrap->bootstrap(array('FrontController', 'Foo'));
// Выполнить все ресурсы и плагины:
$bootstrap->bootstrap();
]]>Реестр ресурсов
Большинство, если не все, методы и плагины ресурсов
будут инициализировать объекты, и во многих случаях эти
объекты будут нужны где-то еще в приложении.
Как получить к ним доступ?
Zend_Application_Bootstrap_BootstrapAbstract
предоставляет локальный реестр для этих объектов.
Для того, чтобы сохранять свои объекты в нем, просто возвращайте
их из своего ресурса.
Для большей гибкости этот реестр внутри себя ссылается на
"контейнеры";
единственное требование состоит в том, чтобы это был объект.
Ресурсы регистрируются как свойства, имена которых совпадают
с именами ресурсов.
По умолчанию используется экземпляр
Zend_Registry, но вы можете при
желании указывать любой другой объект.
Для работы с контейнерами могут использоваться методы
setContainer() и
getContainer().
Метод getResource($resource)
может использоваться для извлечения ресурса из контейнера,
а hasResource($resource) - для
проверки того, был ли зарегистрирован данный ресурс.
Для примера рассмотрим базовый ресурс вида:
Вы можете затем проверять его наличие и/или извлекать его
как показано ниже:
hasResource('view')) {
$view = $bootstrap->getResource('view');
}
// Через контейнер:
$container = $bootstrap->getContainer();
if (isset($container->view)) {
$view = $container->view;
}
]]>
Следует заметить, что реестр и контейнер не являются
глобальными. Это означает, что вам нужно иметь доступ к объекту
загрузки с тем, чтобы можно было извлекать ресурсы.
Zend_Application_Bootstrap_Bootstrap
предоставляет некоторые удобства для этого:
во время выполнения run() он
регистрирует себя в качестве параметра "bootstrap"
во фронт-контроллере, это позволяет извлекать его внутри
маршрутизатора, диспетчера, плагинов и контроллеров действий.
Например, если вы хотите внутри своего контроллера действий
получить доступ к ресурсу вида из примеров выше, то
можете сделать следующее:
getInvokeArg('bootstrap');
$view = $bootstrap->getResource('view');
// ...
}
}
]]>Отслеживание зависимостей
Кроме выполнения методов и плагинов ресурсов,
необходимо также гарантировать, что они выполняются один и
только один раз. Они предназначены для загрузки приложения,
и выполнение их больше одного раза может привести к
непроизводительному расходованию ресурсов.
В то же время некоторые ресурсы могут зависеть от других и
требовать их предварительной загрузки до начала своего
выполнения.
Для решения этих двух проблем
Zend_Application_Bootstrap_BootstrapAbstract
предоставляет простой и эффективный механизм для отслеживания
зависимостей.
Как было сказано ранее, все ресурсы - как методы, так и
плагины, - загружаются путем вызова
bootstrap($resource), где
$resource является именем ресурса или
массивом ресурсов. Если параметр $resource
опущен, то это означает, что все ресурсы должны быть запущены.
Если ресурс зависит от других ресурсов, то он должен вызывать
метод bootstrap() в своем коде
для обеспечения выполнения этих ресурсов.
Последующие вызовы для этих ресурсов будут проигнорированы.
В методе ресурса такой вызов будет выглядеть следующим образом:
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.
Базовый интерфейс довольно прост:
Он определяет только, что ресурс должен принимать опции
через конструктор, иметь механизмы для установки/получения
опций, механизмы для установки/получения объекта загрузочного класса
и метод инициализации.
Для примера предположим, что вы имеете инициализацию вида,
одинаковую для нескольких ваших приложений. Вы используете в
них одну и ту же декларацию DOCTYPE, одни и те же
CSS-стили, скрипты JavaScript,
а также хотите иметь возможность задавать базовый заголовок
документа через конфигурацию.
Ресурс, выполняющий такую инициализацию, может выглядеть следующим
образом:
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", тем самым
обеспечивая использование своего плагина вместо него.