[ZF-8969] Manual:
[zend.git] / documentation / manual / en / module_specs / Zend_Application-TheoryOfOperation.xml
blob16613a8a567693f75e9d8850573bf5bab794a955
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.application.theory-of-operation">
4     <title>Theory of Operation</title>
6     <para>
7         Getting an <acronym>MVC</acronym> application configured and ready to dispatch has
8         required an increasing amount of code as more features become
9         available: setting up the database, configuring your view and view
10         helpers, configuring your layouts, registering plugins, registering
11         action helpers, and more.
12     </para>
14     <para>
15         Additionally, you will often want to reuse the same code to
16         bootstrap your tests, a cronjob, or a service script. While it's
17         possible to simply include your bootstrap script, oftentimes there
18         are initializations that are environment specific – you may not need
19         the <acronym>MVC</acronym> for a cronjob, or just the DB layer for a service script.
20     </para>
22     <para>
23         <classname>Zend_Application</classname> aims to make this easier and to
24         promote reuse by encapsulating bootstrapping into <acronym>OOP</acronym> paradigms.
25     </para>
27     <para>
28         <classname>Zend_Application</classname> is broken into three realms:
29     </para>
31     <itemizedlist>
32         <listitem>
33             <para>
34                 <classname>Zend_Application</classname>: loads the <acronym>PHP</acronym>
35                 environment, including include_paths and autoloading, and instantiates
36                 the requested bootstrap class.
37             </para>
38         </listitem>
40         <listitem>
41             <para>
42                 <classname>Zend_Application_Bootstrap</classname>: provides
43                 interfaces for bootstrap classes.
44                 <classname>Zend_Application_Bootstrap_Bootstrap</classname> provides common
45                 functionality for most bootstrapping needs, including
46                 dependency checking algorithms and the ability to load
47                 bootstrap resources on demand.
48             </para>
49         </listitem>
51         <listitem>
52             <para>
53                 <classname>Zend_Application_Resource</classname> provides an
54                 interface for standard bootstrapping resources that can be
55                 loaded on demand by a bootstrap instance, as well as several
56                 default resource implementations.
57             </para>
58         </listitem>
59     </itemizedlist>
61     <para>
62         Developers create a bootstrap class for their application, extending
63         <classname>Zend_Application_Bootstrap_Bootstrap</classname> or implementing (minimally)
64         <classname>Zend_Application_Bootstrap_Bootstrapper</classname>. The entry point
65         (e.g., <filename>public/index.php</filename>) will load
66         <classname>Zend_Application</classname>, and instantiate it by passing:
67     </para>
69     <itemizedlist>
70         <listitem>
71             <para>
72                 The current environment
73             </para>
74         </listitem>
76         <listitem>
77             <para>
78                 Options for bootstrapping
79             </para>
80         </listitem>
81     </itemizedlist>
83     <para>
84         The bootstrap options include the path to the file containing the
85         bootstrap class and optionally:
86     </para>
88     <itemizedlist>
89         <listitem>
90             <para>
91                 Any extra include_paths to set
92             </para>
93         </listitem>
95         <listitem>
96             <para>
97                 Any additional autoloader namespaces to register
98             </para>
99         </listitem>
101         <listitem>
102             <para>
103                 Any <filename>php.ini</filename> settings to initialize
104             </para>
105         </listitem>
107         <listitem>
108             <para>
109                 The class name for the bootstrap class (if not "Bootstrap")
110             </para>
111         </listitem>
113         <listitem>
114             <para>
115                 Resource prefix to path pairs to use
116             </para>
117         </listitem>
119         <listitem>
120             <para>
121                 Any resources to use (by class name or short name)
122             </para>
123         </listitem>
125         <listitem>
126             <para>
127                 Additional path to a configuration file to load
128             </para>
129         </listitem>
131         <listitem>
132             <para>
133                 Additional configuration options
134             </para>
135         </listitem>
136     </itemizedlist>
138     <para>
139         Options may be an array, a <classname>Zend_Config</classname> object, or the path
140         to a configuration file.
141     </para>
143     <sect2 id="zend.application.theory-of-operation.bootstrap">
144         <title>Bootstrapping</title>
146         <para>
147             <classname>Zend_Application</classname>'s second area of responsibility is
148             executing the application bootstrap. Bootstraps minimally need to
149             implement <classname>Zend_Application_Bootstrap_Bootstrapper</classname>,
150             which defines the following <acronym>API</acronym>:
151         </para>
153         <programlisting language="php"><![CDATA[
154 interface Zend_Application_Bootstrap_Bootstrapper
156     public function __construct($application);
157     public function setOptions(array $options);
158     public function getApplication();
159     public function getEnvironment();
160     public function getClassResources();
161     public function getClassResourceNames();
162     public function bootstrap($resource = null);
163     public function run();
165 ]]></programlisting>
167         <para>
168             This <acronym>API</acronym> allows the bootstrap to accept the environment and
169             configuration from the application object, report the resources its
170             responsible for bootstrapping, and then bootstrap and run the
171             application.
172         </para>
174         <para>
175             You can implement this interface on your own, extend
176             <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>, or use
177             <classname>Zend_Application_Bootstrap_Bootstrap</classname>.
178         </para>
180         <para>
181             Besides this functionality, there are a number of other areas of
182             concern you should familiarize yourself with.
183         </para>
185         <sect3 id="zend.application.theory-of-operation.bootstrap.resource-methods">
186             <title>Resource Methods</title>
188             <para>
189                 The <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
190                 implementation provides a simple convention for defining class
191                 resource methods. Any protected method beginning with a name
192                 prefixed with <emphasis>_init</emphasis> will be considered a resource
193                 method.
194             </para>
196             <para>
197                 To bootstrap a single resource method, use the
198                 <methodname>bootstrap()</methodname> method, and pass it the name of the
199                 resource. The name will be the method name minus the
200                 <emphasis>_init</emphasis> prefix.
201             </para>
203             <para>
204                 To bootstrap several resource methods, pass an array of names.
205                 Too bootstrap all resource methods, pass nothing.
206             </para>
208             <para>
209                 Take the following bootstrap class:
210             </para>
212             <programlisting language="php"><![CDATA[
213 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
215     protected function _initFoo()
216     {
217         // ...
218     }
220     protected function _initBar()
221     {
222         // ...
223     }
225     protected function _initBaz()
226     {
227         // ...
228     }
230 ]]></programlisting>
232             <para>
233                 To bootstrap just the <methodname>_initFoo()</methodname> method, do the
234                 following:
235             </para>
237             <programlisting language="php"><![CDATA[
238 $bootstrap->bootstrap('foo');
239 ]]></programlisting>
241             <para>
242                 To bootstrap the <methodname>_initFoo()</methodname> and
243                 <methodname>_initBar()</methodname> methods, do the following:
244             </para>
246             <programlisting language="php"><![CDATA[
247 $bootstrap->bootstrap(array('foo', 'bar'));
248 ]]></programlisting>
250             <para>
251                 To bootstrap all resource methods, call <methodname>bootstrap()</methodname>
252                 with no arguments:
253             </para>
255             <programlisting language="php"><![CDATA[
256 $bootstrap->bootstrap();
257 ]]></programlisting>
258         </sect3>
260         <sect3 id="zend.application.theory-of-operation.bootstrap.resource-plugins">
261             <title>Bootstraps that use resource plugins</title>
263             <para>
264                 To make your bootstraps more re-usable, we have provided the
265                 ability to push your resources into resource plugin classes.
266                 This allows you to mix and match resources simply via
267                 configuration. We will cover <link
268                     linkend="zend.application.theory-of-operation.resources">how
269                     to create resources</link> later; in
270                 this section we will show you how to utilize them only.
271             </para>
273             <para>
274                 If your bootstrap should be capable of using resource plugins,
275                 you will need to implement an additional interface,
276                 <classname>Zend_Application_Bootstrap_ResourceBootstrapper</classname>.
277                 This interface defines an <acronym>API</acronym> for locating, registering, and
278                 loading resource plugins:
279             </para>
281         <programlisting language="php"><![CDATA[
282 interface Zend_Application_Bootstrap_ResourceBootstrapper
284     public function registerPluginResource($resource, $options = null);
285     public function unregisterPluginResource($resource);
286     public function hasPluginResource($resource);
287     public function getPluginResource($resource);
288     public function getPluginResources();
289     public function getPluginResourceNames();
290     public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader);
291     public function getPluginLoader();
293 ]]></programlisting>
295             <para>
296                 Resource plugins basically provide the ability to create
297                 resource intializers that can be re-used between applications.
298                 This allows you to keep your actual bootstrap relatively clean,
299                 and to introduce new resources without needing to touch your
300                 bootstrap itself.
301             </para>
303             <para>
304                 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> (and
305                 <classname>Zend_Application_Bootstrap_Bootstrap</classname> by extension)
306                 implement this interface as well, allowing you to utilize
307                 resource plugins.
308             </para>
310             <para>
311                 To utilize resource plugins, you must specify them in the
312                 options passed to the application object and/or bootstrap. These
313                 options may come from a configuration file, or be passed in
314                 manually. Options will be of key to options pairs, with the key
315                 representing the resource name. The resource name will be the
316                 segment following the class prefix. For example, the resources
317                 shipped with Zend Framework have the class prefix
318                 "<classname>Zend_Application_Resource_</classname>"; anything following this would
319                 be the name of the resource. As an example,
320             </para>
322             <programlisting language="php"><![CDATA[
323 $application = new Zend_Application(APPLICATION_ENV, array(
324     'resources' => array(
325         'FrontController' => array(
326             'controllerDirectory' => APPLICATION_PATH . '/controllers',
327         ),
328     ),
330 ]]></programlisting>
332             <para>
333                 This indicates that the "FrontController" resource should be
334                 used, with the options specified.
335             </para>
337             <para>
338                 If you begin writing your own resource plugins, or utilize
339                 third-party resource plugins, you will need to tell your
340                 bootstrap where to look for them. Internally, the bootstrap
341                 utilizes <classname>Zend_Loader_PluginLoader</classname>, so you will only
342                 need to indicate the common class prefix an path pairs.
343             </para>
345             <para>
346                 As an example, let's assume you have custom resource plugins in
347                 <filename>APPLICATION_PATH/resources/</filename> and that they share the
348                 common class prefix of <classname>My_Resource</classname>. You would then
349                 pass that information to the application object as follows:
350             </para>
352             <programlisting language="php"><![CDATA[
353 $application = new Zend_Application(APPLICATION_ENV, array(
354     'pluginPaths' => array(
355         'My_Resource' => APPLICATION_PATH . '/resources/',
356     ),
357     'resources' => array(
358         'FrontController' => array(
359             'controllerDirectory' => APPLICATION_PATH . '/controllers',
360         ),
361     ),
363 ]]></programlisting>
365             <para>
366                 You would now be able to use resources from that directory.
367             </para>
369             <para>
370                 Just like resource methods, you use the <methodname>bootstrap()</methodname>
371                 method to execute resource plugins. Just like with resource
372                 methods, you can specify either a single resource plugin,
373                 multiple plugins (via an array), or all plugins. Additionally,
374                 you can mix and match to execute resource methods as well.
375             </para>
377             <programlisting language="php"><![CDATA[
378 // Execute one:
379 $bootstrap->bootstrap('FrontController');
381 // Execute several:
382 $bootstrap->bootstrap(array('FrontController', 'Foo'));
384 // Execute all resource methods and plugins:
385 $bootstrap->bootstrap();
386 ]]></programlisting>
387         </sect3>
389         <sect3 id="zend.application.theory-of-operation.bootstrap.registry">
390             <title>Resource Registry</title>
392             <para>
393                 Many, if not all, of your resource methods or plugins will
394                 initialize objects, and in many cases, these objects will be
395                 needed elsewhere in your application. How can you access them?
396             </para>
398             <para>
399                 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
400                 provides a local registry for these objects. To store your
401                 objects in them, you simply return them from your resources.
402             </para>
404             <para>
405                 For maximum flexibility, this registry is referred to as a
406                 "container" internally; its only requirements are that it is an
407                 object. Resources are then registered as properties named after
408                 the resource name. By default, an instance of
409                 <classname>Zend_Registry</classname> is used, but you may also specify any
410                 other object you wish. The methods <methodname>setContainer()</methodname>
411                 and <methodname>getContainer()</methodname> may be used to manipulate the
412                 container itself. <methodname>getResource($resource)</methodname> can be
413                 used to fetch a given resource from the container, and
414                 <methodname>hasResource($resource)</methodname> to check if the resource has
415                 actually been registered.
416             </para>
418             <para>
419                 As an example, consider a basic view resource:
420             </para>
422             <programlisting language="php"><![CDATA[
423 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
425     protected function _initView()
426     {
427         $view = new Zend_View();
428         // more initialization...
430         return $view;
431     }
433 ]]></programlisting>
435             <para>
436                 You can then check for it and/or fetch it as follows:
437             </para>
439             <programlisting language="php"><![CDATA[
440 // Using the has/getResource() pair:
441 if ($bootstrap->hasResource('view')) {
442     $view = $bootstrap->getResource('view');
445 // Via the container:
446 $container = $bootstrap->getContainer();
447 if (isset($container->view)) {
448     $view = $container->view;
450 ]]></programlisting>
452             <para>
453                 Please note that the registry and also the container is not global. This
454                 means that you need access to the bootstrap in order to fetch
455                 resources. <classname>Zend_Application_Bootstrap_Bootstrap</classname>
456                 provides some convenience for this: during its
457                 <methodname>run()</methodname> execution, it registers itself as the front
458                 controller parameter "bootstrap", which allows you to fetch it
459                 from the router, dispatcher, plugins, and action controllers.
460             </para>
462             <para>
463                 As an example, if you wanted access to the view resource from
464                 above within your action controller, you could do the following:
465             </para>
467             <programlisting language="php"><![CDATA[
468 class FooController extends Zend_Controller_Action
470     public function init()
471     {
472         $bootstrap = $this->getInvokeArg('bootstrap');
473         $view = $bootstrap->getResource('view');
474         // ...
475     }
477 ]]></programlisting>
478         </sect3>
480         <sect3 id="zend.application.theory-of-operation.bootstrap.dependency-tracking">
481             <title>Dependency Tracking</title>
483             <para>
484                 In addition to executing resource methods and plugins, it's
485                 necessary to ensure that these are executed once and once
486                 only; these are meant to bootstrap an application, and
487                 executing multiple times can lead to resource overhead.
488             </para>
490             <para>
491                 At the same time, some resources may depend on other
492                 resources being executed. To solve these two issues,
493                 <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
494                 provides a simple, effective mechanism for dependency
495                 tracking.
496             </para>
498             <para>
499                 As noted previously, all resources -- whether methods or plugins
500                 -- are bootstrapped by calling <methodname>bootstrap($resource)</methodname>,
501                 where <varname>$resource</varname> is the name of a resource, an array
502                 of resources, or, left empty, indicates all resources should be
503                 run.
504             </para>
506             <para>
507                 If a resource depends on another resource, it should call
508                 <methodname>bootstrap()</methodname> within its code to ensure that resource
509                 has been executed. Subsequent calls to it will then be ignored.
510             </para>
512             <para>
513                 In a resource method, such a call would look like this:
514             </para>
516             <programlisting language="php"><![CDATA[
517 class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
519     protected function _initRequest()
520     {
521         // Ensure the front controller is initialized
522         $this->bootstrap('FrontController');
524         // Retrieve the front controller from the bootstrap registry
525         $front = $this->getResource('FrontController');
527         $request = new Zend_Controller_Request_Http();
528         $request->setBaseUrl('/foo');
529         $front->setRequest($request);
531         // Ensure the request is stored in the bootstrap registry
532         return $request;
533     }
535 ]]></programlisting>
536         </sect3>
537     </sect2>
539     <sect2 id="zend.application.theory-of-operation.resources">
540         <title>Resource Plugins</title>
542         <para>
543             <link
544                 linkend="zend.application.theory-of-operation.bootstrap.resource-plugins">As noted
545                 previously</link>, a good way to create re-usable bootstrap resources and to
546             offload much of your coding to discrete classes is to utilize resource
547             plugins. While Zend Framework ships with a number of standard
548             resource plugins, the intention is that developers should write
549             their own to encapsulate their own initialization needs.
550         </para>
552         <para>
553             Resource plugins need only implement
554             <classname>Zend_Application_Resource_Resource</classname>, or, more simply
555             still, extend
556             <classname>Zend_Application_Resource_ResourceAbstract</classname>. The basic
557             interface is simply this:
558         </para>
560         <programlisting language="php"><![CDATA[
561 interface Zend_Application_Resource_Resource
563     public function __construct($options = null);
564     public function setBootstrap(
565         Zend_Application_Bootstrap_Bootstrapper $bootstrap
566     );
567     public function getBootstrap();
568     public function setOptions(array $options);
569     public function getOptions();
570     public function init();
572 ]]></programlisting>
574         <para>
575             The interface defines simply that a resource plugin should accept options
576             to the constructor, have mechanisms for setting and retrieving
577             options, have mechanisms for setting and retrieving the bootstrap
578             object, and an initialization method.
579         </para>
581         <para>
582             As an example, let's assume you have a common view intialization you
583             use in your applications. You have a common doctype, <acronym>CSS</acronym> and
584             JavaScript, and you want to be able to pass in a base document title
585             via configuration. Such a resource plugin might look like this:
586         </para>
588         <programlisting language="php"><![CDATA[
589 class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
591     protected $_view;
593     public function init()
594     {
595         // Return view so bootstrap will store it in the registry
596         return $this->getView();
597     }
599     public function getView()
600     {
601         if (null === $this->_view) {
602             $options = $this->getOptions();
603             $title   = '';
604             if (array_key_exists('title', $options)) {
605                 $title = $options['title'];
606                 unset($options['title']);
607             }
609             $view = new Zend_View($options);
610             $view->doctype('XHTML1_STRICT');
611             $view->headTitle($title);
612             $view->headLink()->appendStylesheet('/css/site.css');
613             $view->headScript()->appendfile('/js/analytics.js');
615             $viewRenderer =
616                 Zend_Controller_Action_HelperBroker::getStaticHelper(
617                     'ViewRenderer'
618                 );
619             $viewRenderer->setView($view);
621             $this->_view = $view;
622         }
623         return $this->_view;
624     }
626 ]]></programlisting>
628         <para>
629             As long as you register the prefix path for this resource plugin,
630             you can then use it in your application. Even better, because it
631             uses the plugin loader, you are effectively overriding the shipped
632             "View" resource plugin, ensuring that your own is used instead.
633         </para>
634     </sect2>
635 </sect1>