1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.application.theory-of-operation">
4 <title>Теоретические основы работы с Zend_Application</title>
7 Получение сконфигурированного <acronym>MVC</acronym>-приложения,
8 готового к обработке запроса,
9 требует наличия дополнительного кода, объем которого зависит от
10 используемого функционала:
11 установка соединения с базой данных, конфигурирование видов и
12 их помощников, конфигурирование макетов (layouts), регистрация плагинов,
13 регистрация помощников действий и так далее.
17 Кроме того, вы можете захотеть повторно использовать один и тот же код
18 для загрузки тестов, сервисных скриптов, скриптов, предназначенных
19 для запуска через крон.
20 Можно просто добавлять свой скрипт загрузки, но часто встречаются
21 инициализации, зависящие от окружения - например, для
22 запуска через крон <acronym>MVC</acronym> может быть лишним, а для
23 сервисного скрипта может быть достаточно только слоя баз данных.
27 <classname>Zend_Application</classname> облегчает управление начальной
28 загрузкой и способствует повторному использованию путем инкапсуляции
29 загрузки в соответствии с парадигмой <acronym>ООП</acronym>.
33 <classname>Zend_Application</classname> состоит из трех областей:
39 <classname>Zend_Application</classname>: загружает окружение
40 <acronym>PHP</acronym>, включая include_paths и автозагрузку
41 (autoloading), инстанцирует запрошенный загрузочный класс.
46 <classname>Zend_Application_Bootstrap</classname>: предоставляет
47 интерфейсы для загрузочных классов.
48 <classname>Zend_Application_Bootstrap_Bootstrap</classname>
49 предоставляет общий функционал, удовлетворяющий большинство
50 нужд по начальной загрузке, включающие в себя алгоритмы проверки
51 зависимостей и возможность загрузки ресурсов по требованию.
56 <classname>Zend_Application_Resource</classname> предоставляет
57 интерфейс для стандартных ресурсов загрузки,
58 которые могут быть загружены по требованию через экземпляр
59 загрузочного класса, и несколько реализаций ресурсов,
60 используемых по умолчанию.
66 Разработчики могут создавать загрузочный класс для приложения,
67 расширяя <classname>Zend_Application_Bootstrap_Bootstrap</classname>
68 или, как минимум, реализуя интерфейс
69 <classname>Zend_Application_Bootstrap_Bootstrapper</classname>.
70 Входная точка (например, <filename>public/index.php</filename>)
71 будет загружать <classname>Zend_Application</classname> и
72 инстанцировать его путем передачи:
89 Опции загрузки включают в себя путь к файлу, содержащему в себе
90 загрузочный класс и, опционально:
96 Любые дополнительные пути для добавления в include_path
101 Любые дополнительные пространства имен автозагрузки,
102 которые требуется зарегистрировать
107 Любые установки <filename>php.ini</filename> для инициализации
112 Имя класса загрузки (если используется имя, отличное от
118 Пары префикс-путь для ресурсов
123 Любые ресурсы для использования (указываются через имя класса
129 Дополнительный путь к загружаемому конфигурационному файлу
134 Дополнительные опции конфигурации
140 Опции могут быть массивом, объектом <classname>Zend_Config</classname>
141 или путью к конфигурационному файлу.
144 <sect2 id="zend.application.theory-of-operation.bootstrap">
145 <title>Начальная загрузка</title>
148 Второй областью отвественности компоненты
149 <classname>Zend_Application</classname> является
150 выполнение загрузки приложения. Загрузочные классы
151 должны как минимум реализовывать интерфейс
152 <classname>Zend_Application_Bootstrap_Bootstrapper</classname>,
153 который определяет следующий <acronym>API</acronym>:
156 <programlisting language="php"><![CDATA[
157 interface Zend_Application_Bootstrap_Bootstrapper
159 public function __construct($application);
160 public function setOptions(array $options);
161 public function getApplication();
162 public function getEnvironment();
163 public function getClassResources();
164 public function getClassResourceNames();
165 public function bootstrap($resource = null);
166 public function run();
171 Этот API позволяет классу загрузки принимать окружение
172 и конфигурацию из объекта приложения, определять ресурсы,
173 за загрузку которых он отвечает, выполнять загрузку и запуск
178 Вы можете сами реализовывать этот интерфейс, расширять
179 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
181 <classname>Zend_Application_Bootstrap_Bootstrap</classname>.
185 Кроме этого функционала есть и другие требующие внимания области,
186 с которыми вы должны ознакомиться.
189 <sect3 id="zend.application.theory-of-operation.bootstrap.resource-methods">
190 <title>Методы ресурсов</title>
193 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
194 предоставляет простое соглашение для определения
195 методов ресурсов. Любой защищенный метод с именем,
196 начинающимся с <emphasis>_init</emphasis>, будет считаться
201 Для того, чтобы запустить один метод ресурса, вызывайте
202 метод <methodname>bootstrap()</methodname> с именем ресурса в
203 качестве аргумента. Именем ресурса будет имя метода без префикса
204 <emphasis>_init</emphasis>.
208 Для того, чтобы запустить несколько методов ресурсов,
209 передавайте массив имен. А для того, чтобы запустить
210 все методы ресурсов, вызывайте метод без аргументов.
214 Возьмем следующий загрузочный класс:
217 <programlisting language="php"><![CDATA[
218 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
220 protected function _initFoo()
225 protected function _initBar()
230 protected function _initBaz()
238 Для того, чтобы запустить только метод
239 <methodname>_initFoo()</methodname>, сделайте следующее:
242 <programlisting language="php"><![CDATA[
243 $bootstrap->bootstrap('foo');
247 Для того, чтобы запустить методы
248 <methodname>_initFoo()</methodname> и
249 <methodname>_initBar()</methodname>, сделайте следующее:
252 <programlisting language="php"><![CDATA[
253 $bootstrap->bootstrap(array('foo', 'bar'));
257 Для того, чтобы запустить все методы ресурсов,
258 используйте <methodname>bootstrap()</methodname> без аргументов:
261 <programlisting language="php"><![CDATA[
262 $bootstrap->bootstrap();
266 <sect3 id="zend.application.theory-of-operation.bootstrap.resource-plugins">
267 <title>Загрузки, использующие плагины ресурсов</title>
270 Для того, чтобы вы могли сделать свои загрузки более пригодными
271 для повторного использования, мы реализовали возможность
272 помещать свои ресурсы в классы-плагины ресурсов.
273 Это позволит вам легко комбинировать ресурсы, используя
275 Ниже будет описание того, <link
276 linkend="zend.application.theory-of-operation.resources">как
277 создавать ресурсы</link>, в данном разделе мы только
278 покажем, как использовать их.
282 Если ваша загрузка должна поддерживать
283 плагины ресурсов, то вам нужно реализовать дополнительный
285 <classname>Zend_Application_Bootstrap_ResourceBootstrapper</classname>.
286 Этот интерфейс определяет <acronym>API</acronym> для
287 определения местонахождения, регистрации и загрузки плагинов
291 <programlisting language="php"><![CDATA[
292 interface Zend_Application_Bootstrap_ResourceBootstrapper
294 public function registerPluginResource($resource, $options = null);
295 public function unregisterPluginResource($resource);
296 public function hasPluginResource($resource);
297 public function getPluginResource($resource);
298 public function getPluginResources();
299 public function getPluginResourceNames();
300 public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader);
301 public function getPluginLoader();
306 Плагины ресурсов в основном дают возможность
307 создавать инициализаторы ресурсов, которые могут повторно
308 использоваться в различных приложениях.
309 Это позволит вам поддерживать порядок в вашей действующей
310 загрузке и внедрять новые ресурсы без
311 необходимости внесения изменений в собственно загрузке.
315 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
316 (и, следовательно, наследующий от него класс
317 <classname>Zend_Application_Bootstrap_Bootstrap</classname>)
318 реализуют этот интерфейс, позволяя вам использовать
323 Для того, чтобы использовать плагины ресурсов, вы должны
324 указывать их в опциях, передаваемых объектам приложения и/или
325 загрузки. Эти опции могут указываться через конфигурационный
326 файл или передаваться вручную.
327 Опции будут массивом пар ключ/опции, где ключом является
328 имя ресурса. Именем ресурса будет часть строки, следующая
329 после префикса класса. Например,
330 ресурсы, поставляемые c Zend Framework'ом, имеют префикс класса
331 "<classname>Zend_Application_Resource_</classname>", все, что
332 следует за ним, будет именем ресурса. Например:
335 <programlisting language="php"><![CDATA[
336 $application = new Zend_Application(APPLICATION_ENV, array(
337 'resources' => array(
338 'FrontController' => array(
339 'controllerDirectory' => APPLICATION_PATH . '/controllers',
346 Это означает, что должен использоваться ресурс
347 "FrontController" с указанными опциями.
351 Если вы планируете писать собственные плагины ресурсов
352 либо добавить сторонние, то нужно будет указать вашей
353 загрузке, где их искать.
354 Внутри себя загрузка использует
355 <classname>Zend_Loader_PluginLoader</classname>, поэтому
356 достаточно указать префикс класса и путь к директории с
361 Для примера предположим, что вы имеете свои плагины ресурсов
362 в директории <filename>APPLICATION_PATH/resources/</filename>,
363 и они используют общий префикс
364 <classname>My_Resource</classname>.
365 Вы можете передать эту информацию объекту приложения так,
369 <programlisting language="php"><![CDATA[
370 $application = new Zend_Application(APPLICATION_ENV, array(
371 'pluginPaths' => array(
372 'My_Resource' => APPLICATION_PATH . '/resources/',
374 'resources' => array(
375 'FrontController' => array(
376 'controllerDirectory' => APPLICATION_PATH . '/controllers',
383 После этого вы можете использовать ресурсы из этой директории.
387 Так же, как и в случае с методами ресурсов, вы используете
388 метод <methodname>bootstrap()</methodname> для выполнения
390 И точно так же вы можете указывать один плагин ресурса,
391 несколько плагинов ресурсов (через массив), либо запускать все плагины
392 сразу. Кроме того, вы можете комбинировать их с методами
396 <programlisting language="php"><![CDATA[
398 $bootstrap->bootstrap('FrontController');
400 // Выполнить несколько:
401 $bootstrap->bootstrap(array('FrontController', 'Foo'));
403 // Выполнить все ресурсы и плагины:
404 $bootstrap->bootstrap();
408 <sect3 id="zend.application.theory-of-operation.bootstrap.registry">
409 <title>Реестр ресурсов</title>
412 Большинство, если не все, методы и плагины ресурсов
413 будут инициализировать объекты, и во многих случаях эти
414 объекты будут нужны где-то еще в приложении.
415 Как получить к ним доступ?
419 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
420 предоставляет локальный реестр для этих объектов.
421 Для того, чтобы сохранять свои объекты в нем, просто возвращайте
422 их из своего ресурса.
426 Для большей гибкости этот реестр внутри себя ссылается на
428 единственное требование состоит в том, чтобы это был объект.
429 Ресурсы регистрируются как свойства, имена которых совпадают
431 По умолчанию используется экземпляр
432 <classname>Zend_Registry</classname>, но вы можете при
433 желании указывать любой другой объект.
434 Для работы с контейнерами могут использоваться методы
435 <methodname>setContainer()</methodname> и
436 <methodname>getContainer()</methodname>.
437 Метод <methodname>getResource($resource)</methodname>
438 может использоваться для извлечения ресурса из контейнера,
439 а <methodname>hasResource($resource)</methodname> - для
440 проверки того, был ли зарегистрирован данный ресурс.
444 Для примера рассмотрим базовый ресурс вида:
447 <programlisting language="php"><![CDATA[
448 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
450 protected function _initView()
452 $view = new Zend_View();
453 // дальнейшая инициализация...
461 Вы можете затем проверять его наличие и/или извлекать его
465 <programlisting language="php"><![CDATA[
466 // Использование пары has/getResource()
467 if ($bootstrap->hasResource('view')) {
468 $view = $bootstrap->getResource('view');
472 $container = $bootstrap->getContainer();
473 if (isset($container->view)) {
474 $view = $container->view;
479 Следует заметить, что реестр и контейнер не являются
480 глобальными. Это означает, что вам нужно иметь доступ к объекту
481 загрузки с тем, чтобы можно было извлекать ресурсы.
482 <classname>Zend_Application_Bootstrap_Bootstrap</classname>
483 предоставляет некоторые удобства для этого:
484 во время выполнения <methodname>run()</methodname> он
485 регистрирует себя в качестве параметра "bootstrap"
486 во фронт-контроллере, это позволяет извлекать его внутри
487 маршрутизатора, диспетчера, плагинов и контроллеров действий.
491 Например, если вы хотите внутри своего контроллера действий
492 получить доступ к ресурсу вида из примеров выше, то
493 можете сделать следующее:
496 <programlisting language="php"><![CDATA[
497 class FooController extends Zend_Controller_Action
499 public function init()
501 $bootstrap = $this->getInvokeArg('bootstrap');
502 $view = $bootstrap->getResource('view');
509 <sect3 id="zend.application.theory-of-operation.bootstrap.dependency-tracking">
510 <title>Отслеживание зависимостей</title>
513 Кроме выполнения методов и плагинов ресурсов,
514 необходимо также гарантировать, что они выполняются один и
515 только один раз. Они предназначены для загрузки приложения,
516 и выполнение их больше одного раза может привести к
517 непроизводительному расходованию ресурсов.
521 В то же время некоторые ресурсы могут зависеть от других и
522 требовать их предварительной загрузки до начала своего
524 Для решения этих двух проблем
525 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
526 предоставляет простой и эффективный механизм для отслеживания
531 Как было сказано ранее, все ресурсы - как методы, так и
532 плагины, - загружаются путем вызова
533 <methodname>bootstrap($resource)</methodname>, где
534 <varname>$resource</varname> является именем ресурса или
535 массивом ресурсов. Если параметр <varname>$resource</varname>
536 опущен, то это означает, что все ресурсы должны быть запущены.
540 Если ресурс зависит от других ресурсов, то он должен вызывать
541 метод <methodname>bootstrap()</methodname> в своем коде
542 для обеспечения выполнения этих ресурсов.
543 Последующие вызовы для этих ресурсов будут проигнорированы.
547 В методе ресурса такой вызов будет выглядеть следующим образом:
550 <programlisting language="php"><![CDATA[
551 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
553 protected function _initRequest()
555 // Обеспечение инициализации контроллера
556 $this->bootstrap('FrontController');
558 // Извлечение фронт-контроллера из реестра загрузки
559 $front = $this->getResource('FrontController');
561 $request = new Zend_Controller_Request_Http();
562 $request->setBaseUrl('/foo');
563 $front->setRequest($request);
565 // Обеспечение сохранения запроса в реестре загрузки
573 <sect2 id="zend.application.theory-of-operation.resources">
574 <title>Плагины ресурсов</title>
577 <link linkend="zend.application.theory-of-operation.bootstrap.resource-plugins">Как
578 было сказано ранее</link>,
579 хорошим способом создания повторно используемых ресурсов загрузки
580 и выделения кода в отдельные классы является
581 использование плагинов ресурсов.
582 Хотя Zend Framework поставляется с набором стандартных плагинов
583 ресурсов, замысел состоит в том, что разработчики должны
584 писать собственные плагины с целью инкапсуляции собственного
585 кода, предназначенного для инициализации.
589 Ресурсы должны только реализовывать интерфейс
590 <classname>Zend_Application_Resource_Resource</classname> или, что
591 является более простым вариантом, расширять абстрактный класс
592 <classname>Zend_Application_Resource_ResourceAbstract</classname>.
593 Базовый интерфейс довольно прост:
596 <programlisting language="php"><![CDATA[
597 interface Zend_Application_Resource_Resource
599 public function __construct($options = null);
600 public function setBootstrap(
601 Zend_Application_Bootstrap_Bootstrapper $bootstrap
603 public function getBootstrap();
604 public function setOptions(array $options);
605 public function getOptions();
606 public function init();
611 Он определяет только, что ресурс должен принимать опции
612 через конструктор, иметь механизмы для установки/получения
613 опций, механизмы для установки/получения объекта загрузочного класса
614 и метод инициализации.
618 Для примера предположим, что вы имеете инициализацию вида,
619 одинаковую для нескольких ваших приложений. Вы используете в
620 них одну и ту же декларацию DOCTYPE, одни и те же
621 <acronym>CSS</acronym>-стили, скрипты JavaScript,
622 а также хотите иметь возможность задавать базовый заголовок
623 документа через конфигурацию.
624 Ресурс, выполняющий такую инициализацию, может выглядеть следующим
628 <programlisting language="php"><![CDATA[
629 class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
633 public function init()
635 // Возвращает вид, таким образом, он будет сохранен в реестре
636 return $this->getView();
639 public function getView()
641 if (null === $this->_view) {
642 $options = $this->getOptions();
644 if (array_key_exists('title', $options)) {
645 $title = $options['title'];
646 unset($options['title']);
649 $view = new Zend_View($options);
650 $view->doctype('XHTML1_STRICT');
651 $view->headTitle($title);
652 $view->headLink()->appendStylesheet('/css/site.css');
653 $view->headScript()->appendfile('/js/analytics.js');
656 Zend_Controller_Action_HelperBroker::getStaticHelper(
659 $viewRenderer->setView($view);
661 $this->_view = $view;
669 Зарегистрировав путь к этому плагину ресурса, вы можете
670 использовать его в своем приложении. Сверх того, благодаря
671 использованию загрузчика плагинов вы эффективно
672 переопределите идущий в поставке плагин ресурса "View", тем самым
673 обеспечивая использование своего плагина вместо него.