| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.application.theory-of-operation">
- <title>Theory of Operation</title>
- <para>
- Getting an <acronym>MVC</acronym> application configured and ready to dispatch has
- required an increasing amount of code as more features become
- available: setting up the database, configuring your view and view
- helpers, configuring your layouts, registering plugins, registering
- action helpers, and more.
- </para>
- <para>
- Additionally, you will often want to reuse the same code to
- bootstrap your tests, a cronjob, or a service script. While it's
- possible to simply include your bootstrap script, oftentimes there
- are initializations that are environment specific – you may not need
- the <acronym>MVC</acronym> for a cronjob, or just the DB layer for a service script.
- </para>
- <para>
- <classname>Zend_Application</classname> aims to make this easier and to
- promote reuse by encapsulating bootstrapping into <acronym>OOP</acronym> paradigms.
- </para>
- <para>
- <classname>Zend_Application</classname> is broken into three realms:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Application</classname>: loads the <acronym>PHP</acronym>
- environment, including include_paths and autoloading, and instantiates
- the requested bootstrap class.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Bootstrap</classname>: provides
- interfaces for bootstrap classes.
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> provides common
- functionality for most bootstrapping needs, including
- dependency checking algorithms and the ability to load
- bootstrap resources on demand.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Resource</classname> provides an
- interface for standard bootstrapping resources that can be
- loaded on demand by a bootstrap instance, as well as several
- default resource implementations.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Developers create a bootstrap class for their application, extending
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> or implementing (minimally)
- <classname>Zend_Application_Bootstrap_Bootstrapper</classname>. The entry point
- (e.g., <filename>public/index.php</filename>) will load
- <classname>Zend_Application</classname>, and instantiate it by passing:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- The current environment
- </para>
- </listitem>
- <listitem>
- <para>
- Options for bootstrapping
- </para>
- </listitem>
- </itemizedlist>
- <para>
- The bootstrap options include the path to the file containing the
- bootstrap class and optionally:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Any extra include_paths to set
- </para>
- </listitem>
- <listitem>
- <para>
- Any additional autoloader namespaces to register
- </para>
- </listitem>
- <listitem>
- <para>
- Any <filename>php.ini</filename> settings to initialize
- </para>
- </listitem>
- <listitem>
- <para>
- The class name for the bootstrap class (if not "Bootstrap")
- </para>
- </listitem>
- <listitem>
- <para>
- Resource prefix to path pairs to use
- </para>
- </listitem>
- <listitem>
- <para>
- Any resources to use (by class name or short name)
- </para>
- </listitem>
- <listitem>
- <para>
- Additional path to a configuration file to load
- </para>
- </listitem>
- <listitem>
- <para>
- Additional configuration options
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Options may be an array, a <classname>Zend_Config</classname> object, or the path
- to a configuration file.
- </para>
- <sect2 id="zend.application.theory-of-operation.bootstrap">
- <title>Bootstrapping</title>
- <para>
- <classname>Zend_Application</classname>'s second area of responsibility is
- executing the application bootstrap. Bootstraps minimally need to
- implement <classname>Zend_Application_Bootstrap_Bootstrapper</classname>,
- which defines the following <acronym>API</acronym>:
- </para>
- <programlisting language="php"><![CDATA[
- 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();
- }
- ]]></programlisting>
- <para>
- This <acronym>API</acronym> allows the bootstrap to accept the environment and
- configuration from the application object, report the resources its
- responsible for bootstrapping, and then bootstrap and run the
- application.
- </para>
- <para>
- You can implement this interface on your own, extend
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>, or use
- <classname>Zend_Application_Bootstrap_Bootstrap</classname>.
- </para>
- <para>
- Besides this functionality, there are a number of other areas of
- concern you should familiarize yourself with.
- </para>
- <sect3 id="zend.application.theory-of-operation.bootstrap.resource-methods">
- <title>Resource Methods</title>
- <para>
- The <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
- implementation provides a simple convention for defining class
- resource methods. Any protected method beginning with a name
- prefixed with <emphasis>_init</emphasis> will be considered a resource
- method.
- </para>
- <para>
- To bootstrap a single resource method, use the
- <methodname>bootstrap()</methodname> method, and pass it the name of the
- resource. The name will be the method name minus the
- <emphasis>_init</emphasis> prefix.
- </para>
- <para>
- To bootstrap several resource methods, pass an array of names.
- Too bootstrap all resource methods, pass nothing.
- </para>
- <para>
- Take the following bootstrap class:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initFoo()
- {
- // ...
- }
- protected function _initBar()
- {
- // ...
- }
- protected function _initBaz()
- {
- // ...
- }
- }
- ]]></programlisting>
- <para>
- To bootstrap just the <methodname>_initFoo()</methodname> method, do the
- following:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap('foo');
- ]]></programlisting>
- <para>
- To bootstrap the <methodname>_initFoo()</methodname> and
- <methodname>_initBar()</methodname> methods, do the following:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap(array('foo', 'bar'));
- ]]></programlisting>
- <para>
- To bootstrap all resource methods, call <methodname>bootstrap()</methodname>
- with no arguments:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.application.theory-of-operation.bootstrap.resource-plugins">
- <title>Bootstraps that use resource plugins</title>
- <para>
- To make your bootstraps more re-usable, we have provided the
- ability to push your resources into resource plugin classes.
- This allows you to mix and match resources simply via
- configuration. We will cover <link
- linkend="zend.application.theory-of-operation.resources">how
- to create resources</link> later; in
- this section we will show you how to utilize them only.
- </para>
- <para>
- If your bootstrap should be capable of using resource plugins,
- you will need to implement an additional interface,
- <classname>Zend_Application_Bootstrap_ResourceBootstrapper</classname>.
- This interface defines an <acronym>API</acronym> for locating, registering, and
- loading resource plugins:
- </para>
- <programlisting language="php"><![CDATA[
- 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();
- }
- ]]></programlisting>
- <para>
- Resource plugins basically provide the ability to create
- resource intializers that can be re-used between applications.
- This allows you to keep your actual bootstrap relatively clean,
- and to introduce new resources without needing to touch your
- bootstrap itself.
- </para>
- <para>
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> (and
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> by extension)
- implement this interface as well, allowing you to utilize
- resource plugins.
- </para>
- <para>
- To utilize resource plugins, you must specify them in the
- options passed to the application object and/or bootstrap. These
- options may come from a configuration file, or be passed in
- manually. Options will be of key to options pairs, with the key
- representing the resource name. The resource name will be the
- segment following the class prefix. For example, the resources
- shipped with Zend Framework have the class prefix
- "<classname>Zend_Application_Resource_</classname>"; anything following this would
- be the name of the resource. As an example,
- </para>
- <programlisting language="php"><![CDATA[
- $application = new Zend_Application(APPLICATION_ENV, array(
- 'resources' => array(
- 'FrontController' => array(
- 'controllerDirectory' => APPLICATION_PATH . '/controllers',
- ),
- ),
- ));
- ]]></programlisting>
- <para>
- This indicates that the "FrontController" resource should be
- used, with the options specified.
- </para>
- <para>
- If you begin writing your own resource plugins, or utilize
- third-party resource plugins, you will need to tell your
- bootstrap where to look for them. Internally, the bootstrap
- utilizes <classname>Zend_Loader_PluginLoader</classname>, so you will only
- need to indicate the common class prefix an path pairs.
- </para>
- <para>
- As an example, let's assume you have custom resource plugins in
- <filename>APPLICATION_PATH/resources/</filename> and that they share the
- common class prefix of <classname>My_Resource</classname>. You would then
- pass that information to the application object as follows:
- </para>
- <programlisting language="php"><![CDATA[
- $application = new Zend_Application(APPLICATION_ENV, array(
- 'pluginPaths' => array(
- 'My_Resource' => APPLICATION_PATH . '/resources/',
- ),
- 'resources' => array(
- 'FrontController' => array(
- 'controllerDirectory' => APPLICATION_PATH . '/controllers',
- ),
- ),
- ));
- ]]></programlisting>
- <para>
- You would now be able to use resources from that directory.
- </para>
- <para>
- Just like resource methods, you use the <methodname>bootstrap()</methodname>
- method to execute resource plugins. Just like with resource
- methods, you can specify either a single resource plugin,
- multiple plugins (via an array), or all plugins. Additionally,
- you can mix and match to execute resource methods as well.
- </para>
- <programlisting language="php"><![CDATA[
- // Execute one:
- $bootstrap->bootstrap('FrontController');
- // Execute several:
- $bootstrap->bootstrap(array('FrontController', 'Foo'));
- // Execute all resource methods and plugins:
- $bootstrap->bootstrap();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.application.theory-of-operation.bootstrap.registry">
- <title>Resource Registry</title>
- <para>
- Many, if not all, of your resource methods or plugins will
- initialize objects, and in many cases, these objects will be
- needed elsewhere in your application. How can you access them?
- </para>
- <para>
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
- provides a local registry for these objects. To store your
- objects in them, you simply return them from your resources.
- </para>
- <para>
- For maximum flexibility, this registry is referred to as a
- "container" internally; its only requirements are that it is an
- object. Resources are then registered as properties named after
- the resource name. By default, an instance of
- <classname>Zend_Registry</classname> is used, but you may also specify any
- other object you wish. The methods <methodname>setContainer()</methodname>
- and <methodname>getContainer()</methodname> may be used to manipulate the
- container itself. <methodname>getResource($resource)</methodname> can be
- used to fetch a given resource from the container, and
- <methodname>hasResource($resource)</methodname> to check if the resource has
- actually been registered.
- </para>
- <para>
- As an example, consider a basic view resource:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initView()
- {
- $view = new Zend_View();
- // more initialization...
- return $view;
- }
- }
- ]]></programlisting>
- <para>
- You can then check for it and/or fetch it as follows:
- </para>
- <programlisting language="php"><![CDATA[
- // Using the has/getResource() pair:
- if ($bootstrap->hasResource('view')) {
- $view = $bootstrap->getResource('view');
- }
- // Via the container:
- $container = $bootstrap->getContainer();
- if (isset($container->view)) {
- $view = $container->view;
- }
- ]]></programlisting>
- <para>
- Please note that the registry and also the container is not global. This
- means that you need access to the bootstrap in order to fetch
- resources. <classname>Zend_Application_Bootstrap_Bootstrap</classname>
- provides some convenience for this: during its
- <methodname>run()</methodname> execution, it registers itself as the front
- controller parameter "bootstrap", which allows you to fetch it
- from the router, dispatcher, plugins, and action controllers.
- </para>
- <para>
- As an example, if you wanted access to the view resource from
- above within your action controller, you could do the following:
- </para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function init()
- {
- $bootstrap = $this->getInvokeArg('bootstrap');
- $view = $bootstrap->getResource('view');
- // ...
- }
- }
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.application.theory-of-operation.bootstrap.dependency-tracking">
- <title>Dependency Tracking</title>
- <para>
- In addition to executing resource methods and plugins, it's
- necessary to ensure that these are executed once and once
- only; these are meant to bootstrap an application, and
- executing multiple times can lead to resource overhead.
- </para>
- <para>
- At the same time, some resources may depend on other
- resources being executed. To solve these two issues,
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
- provides a simple, effective mechanism for dependency
- tracking.
- </para>
- <para>
- As noted previously, all resources -- whether methods or plugins
- -- are bootstrapped by calling <methodname>bootstrap($resource)</methodname>,
- where <varname>$resource</varname> is the name of a resource, an array
- of resources, or, left empty, indicates all resources should be
- run.
- </para>
- <para>
- If a resource depends on another resource, it should call
- <methodname>bootstrap()</methodname> within its code to ensure that resource
- has been executed. Subsequent calls to it will then be ignored.
- </para>
- <para>
- In a resource method, such a call would look like this:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initRequest()
- {
- // Ensure the front controller is initialized
- $this->bootstrap('FrontController');
- // Retrieve the front controller from the bootstrap registry
- $front = $this->getResource('FrontController');
- $request = new Zend_Controller_Request_Http();
- $request->setBaseUrl('/foo');
- $front->setRequest($request);
- // Ensure the request is stored in the bootstrap registry
- return $request;
- }
- }
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="zend.application.theory-of-operation.resources">
- <title>Resource Plugins</title>
- <para>
- <link
- linkend="zend.application.theory-of-operation.bootstrap.resource-plugins">As noted
- previously</link>, a good way to create re-usable bootstrap resources and to
- offload much of your coding to discrete classes is to utilize resource
- plugins. While Zend Framework ships with a number of standard
- resource plugins, the intention is that developers should write
- their own to encapsulate their own initialization needs.
- </para>
- <para>
- Resource plugins need only implement
- <classname>Zend_Application_Resource_Resource</classname>, or, more simply
- still, extend
- <classname>Zend_Application_Resource_ResourceAbstract</classname>. The basic
- interface is simply this:
- </para>
- <programlisting language="php"><![CDATA[
- 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();
- }
- ]]></programlisting>
- <para>
- The interface defines simply that a resource plugin should accept options
- to the constructor, have mechanisms for setting and retrieving
- options, have mechanisms for setting and retrieving the bootstrap
- object, and an initialization method.
- </para>
- <para>
- As an example, let's assume you have a common view intialization you
- use in your applications. You have a common doctype, <acronym>CSS</acronym> and
- JavaScript, and you want to be able to pass in a base document title
- via configuration. Such a resource plugin might look like this:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
- {
- protected $_view;
- public function init()
- {
- // Return view so bootstrap will store it in the registry
- 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;
- }
- }
- ]]></programlisting>
- <para>
- As long as you register the prefix path for this resource plugin,
- you can then use it in your application. Even better, because it
- uses the plugin loader, you are effectively overriding the shipped
- "View" resource plugin, ensuring that your own is used instead.
- </para>
- </sect2>
- </sect1>
|