| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- <?xml version="1.0" encoding="utf-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.application.theory-of-operation">
- <title>Théorie générale</title>
- <para>
- Monter une application <acronym>MVC</acronym> configurée et prête à être lancée requière de
- plus en plus de code au fur et à mesure de l'ajout de fonctionnalités : monter une base
- de données, configurer la vue et ses aides, les layouts, enregistrer des plugins, des aides
- d'action et bien plus encore...
- </para>
- <para>
- Aussi, vous réutiliserez souvent le même code dans vos tests, dans une tâche cron ou
- encore un service. Il est certes possible d'inclure le script de bootstrap dans de tels cas,
- mais souvent des variables seront dépendantes de l'environnement. Par exemple, vous n'aurez
- pas besoin de <acronym>MVC</acronym> dans une tâche cron, ou alors vous aurez juste besoin
- de l'accès à la base de données dans un script de service.
- </para>
- <para>
- <classname>Zend_Application</classname> a pour but de simplifier ces processus et de
- promouvoir la réutilisabilité de code en encapsulant les étages de définition du bootstrap
- en concepts orientés objet (<acronym>OO</acronym>).
- </para>
- <para><classname>Zend_Application</classname> se décompose en 3 parties :</para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Application</classname> charge l'environnement
- <acronym>PHP</acronym>, à savoir les include_paths et les autoloads, et instancie
- la classe de bootstrap demandée.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Bootstrap</classname> regroupe les interfaces pour les
- classes de bootstrap. <classname>Zend_Application_Bootstrap_Bootstrap</classname>
- propose des fonctionnalités de base concernant l'amorçage (le bootstrap), à savoir
- des algorithmes de vérification des dépendances et la possibilité de charger des
- ressources à la demande.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Resource</classname> est une interface pour les
- ressources de bootstrap qui peuvent être chargées à la demande depuis les instances
- de bootstrap.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Les développeurs créent une classe de bootstrap pour leur application en étendant
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> ou en implémentant (au minimum)
- <classname>Zend_Application_Bootstrap_Bootstrapper</classname>. Le point d'entrée
- (<filename>public/index.php</filename>) chargera <classname>Zend_Application</classname>
- en l'instanciant et en lui passant :
- </para>
- <itemizedlist>
- <listitem>
- <para>L'environnement courant</para>
- </listitem>
- <listitem>
- <para>Des options de bootstrapping</para>
- </listitem>
- </itemizedlist>
- <para>
- Les options de bootstrap incluent le chemin vers le fichier contenant la classe de
- bootstrap, et optionnellement :
- </para>
- <itemizedlist>
- <listitem>
- <para>Des include_paths supplémentaires</para>
- </listitem>
- <listitem>
- <para>Des espaces de nom d'autoload à enregistrer</para>
- </listitem>
- <listitem>
- <para>Des paramètres <filename>php.ini</filename> à initialiser</para>
- </listitem>
- <listitem>
- <para>Le nom de la classe pour le bootstrap (sinon "Bootstrap" sera utilisée)</para>
- </listitem>
- <listitem>
- <para>Des paires préfixe / chemin pour les ressources à utiliser</para>
- </listitem>
- <listitem>
- <para>N'importe quelle ressource à utiliser (nom de classe ou nom court)</para>
- </listitem>
- <listitem>
- <para>Des chemins additionnels vers un fichier de configuration à charger</para>
- </listitem>
- <listitem>
- <para>Des options de configuration supplémentaires</para>
- </listitem>
- </itemizedlist>
- <para>
- Les options peuvent être un tableau, un objet <classname>Zend_Config</classname>, ou
- le chemin vers un fichier de configuration.
- </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>
- Resources 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>
|