| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: 20763 -->
- <sect1 id="zend.application.theory-of-operation">
- <title>Arbeitsweise</title>
- <para>
- Um eine <acronym>MVC</acronym>-Anwendung zu konfigurieren und bereit zur Auslieferung
- zu bekommen wird ein immer größerer Anteil an Code benötigt, sobald mehr Features verfügbar
- sind: Setzen der Datenbank, Konfiguration der View und View Helfer, Konfiguration der
- Layouts, Registrierung der Plugins, Registrierung der Aktion Helfer, und andere.
- </para>
- <para>
- Zusätzlich will man oft den gleichen Code wiederverwenden, um Tests zu bootstrappen, einen
- Cronjob, oder ein Service-Skript zu haben. Wärend es sehr einfach ist, sein Bootstrap-Skript
- einzubauen, gibt es oft Initialisierungen, die abhängig von der Umgebung sind - man
- benötigt kein <acronym>MVC</acronym> für einen Cronjob, oder nur den DB-Layer für ein
- Service-Skript.
- </para>
- <para>
- <classname>Zend_Application</classname> zielt darauf ab, das alles einfacher zu machen und
- bietet Wiederverwendbarkeit durch die Kapselung des Bootstrapping in
- <acronym>OOP</acronym>-Paradigmen.
- </para>
- <para>
- <classname>Zend_Application</classname> ist in drei Bereiche geteilt:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Application</classname>: Lädt die <acronym>PHP</acronym>-Umgebung,
- inklusive Inklude-Pfade und Autoloading, und instanziiert die benötigte
- Bootstrap-Klasse.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Bootstrap</classname>: Bietet Interfaces für
- Bootstrap-Klassen. <classname>Zend_Application_Bootstrap_Bootstrap</classname> bietet
- übliche Funktionalitäten für die meisten Notwendigkeiten des Bootstrappings,
- inklusive Algorithmen um Abhängigkeiten zu prüfen und die Möglichkeit
- Bootstrap-Ressourcen bei Bedarf zu laden.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Application_Resource</classname> bietet ein Interface für Standard
- Bootstrap-Ressourcen, die bei Bedarf von einer Bootstrap-Instanz geladen werden
- können, sowie verschiedene standardmäßige Ressource-Implementationen.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Entwickler erstellen eine Bootstrap-Klasse für ihre Anwendung und erweitern
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> oder implementieren (mindestens)
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>. Der Einstiegspunkt
- (z.B. <filename>public/index.php</filename>) lädt <classname>Zend_Application</classname>
- und initialisiert sie, indem folgendes übergeben wird:
- </para>
- <itemizedlist>
- <listitem><para>Die aktuelle Umgebung</para></listitem>
- <listitem><para>Optionen für das Bootstrapping</para></listitem>
- </itemizedlist>
- <para>
- Die Bootstrap-Optionen enthalten den Pfad zur Datei, welche die Bootstrap-Klasse enthält und
- optional:
- </para>
- <itemizedlist>
- <listitem>
- <para>Jeden include_path der extra zu setzen ist</para>
- </listitem>
- <listitem>
- <para>Jeden Autoloader Namespace, der zusätzlich zu registrieren ist</para>
- </listitem>
- <listitem>
- <para>Jede <filename>php.ini</filename> Einstellung, die zu initialisieren ist</para>
- </listitem>
- <listitem>
- <para>
- Den Klassennamen für die Bootstrap-Klasse (wenn diese nicht "Bootstrap" ist)
- </para>
- </listitem>
- <listitem>
- <para>Ressourcen-Präfix zu Pfadpaaren, die zu verwenden sind</para>
- </listitem>
- <listitem>
- <para>Jede Ressource, die zu verwenden ist (durch Name der Klasse oder Kurzname)</para>
- </listitem>
- <listitem>
- <para>Zusätzliche Pfade zu einer Konfigurationsdatei, die zu laden ist</para>
- </listitem>
- <listitem>
- <para>Zusätzliche Konfigurationsoptionen</para>
- </listitem>
- </itemizedlist>
- <para>
- Optionen können ein Array, ein <classname>Zend_Config</classname>-Objekt, oder der Pfad zu
- einer Konfigurationsdatei sein.
- </para>
- <sect2 id="zend.application.theory-of-operation.bootstrap">
- <title>Bootstrapping</title>
- <para>
- Der zweite Aufgabenbereich von<classname>Zend_Application</classname> ist die Ausführung
- des Bootstraps der Anwendung. Bootstraps müssen mindestens
- <classname>Zend_Application_Bootstrap_Bootstrapper</classname> implementieren, welches
- die folgende <acronym>API</acronym> definiert:
- </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>
- Diese <acronym>API</acronym> erlaubt es dem Bootstrap die Umgebung und die
- Konfiguration vom Objekt der Anwendung zu akzeptieren, die Ressourcen die für das
- Bootstrapping verantwortlich sind zu melden, und dann das Bootstrappen ausführen und
- die Anwendung zu starten.
- </para>
- <para>
- Man kann dieses Interface selbst implementieren,
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> erweitern, oder
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> verwenden.
- </para>
- <para>
- Neben dieser Funktionalität gibt es eine Anzahl anderer Gebiete von Interesse mit denen
- man vertraut sein sollte.
- </para>
- <sect3 id="zend.application.theory-of-operation.bootstrap.resource-methods">
- <title>Methoden für Ressourcen</title>
- <para>
- Die Implementation von
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> bietet eine
- einfache Konvention für die Definition von Methoden für Ressourcen-Klassen. Jede
- geschützte Methode (protected), deren Name mit <emphasis>_init</emphasis> beginnt,
- wird als Ressourcemethode angenommen.
- </para>
- <para>
- Um eine einzelne Ressource-Methode zu bootstrappen, muß die
- Methode <methodname>bootstrap()</methodname> verwendet und der Name der Ressource
- übergeben werden. Der Name ist der Name der Methode ohne das
- Präfix <emphasis>_init</emphasis>.
- </para>
- <para>
- Um mehrere Ressourcen-Methoden zu bootstrappen, muß ein Array von Namen übergeben
- werden. Um alle Ressourcen-Methoden zu bootstrappen, darf nichts übergeben werden.
- </para>
- <para>
- Nehmen wir die folgende Bootstrap-Klasse an:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initFoo()
- {
- // ...
- }
- protected function _initBar()
- {
- // ...
- }
- protected function _initBaz()
- {
- // ...
- }
- }
- ]]></programlisting>
- <para>
- Um nur die Methode <methodname>_initFoo()</methodname> zu bootstrappen, machen wir
- das folgende:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap('foo');
- ]]></programlisting>
- <para>
- Um die Methoden <methodname>_initFoo()</methodname> und
- <methodname>_initBar()</methodname> zu bootstrappen, machen wir das folgende:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap(array('foo', 'bar'));
- ]]></programlisting>
- <para>
- Um alle Ressourcen-Methoden zu bootstrappen, rufen wir
- <methodname>bootstrap()</methodname> ohne Argumente auf:
- </para>
- <programlisting language="php"><![CDATA[
- $bootstrap->bootstrap();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.application.theory-of-operation.bootstrap.resource-plugins">
- <title>Bootstraps, die Ressourcen-Plugins benutzen</title>
- <para>
- Um Bootstraps wiederverwendbarer zu machen, wurde die Fähigkeit zur Verfügung
- gestellt, Ressourcen in Ressource-Plugin-Klassen zu geben. Das erlaubt es, Ressourcen
- einfach über die Konfiguration zu mischen und zu sehen ob sie passen. Wir behandeln
- später <link linkend="zend.application.theory-of-operation.resources">wie
- Ressourcen erstellt werden</link>; in diesem Abschnitt zeigen wir nur, wie sie
- angepasst werden können.
- </para>
- <para>
- Wenn das Bootstrap dazu in der Lage sein soll, Ressource-Plugins zu verwenden, muß
- man ein zusätzliches Interface implementieren,
- <classname>Zend_Application_Bootstrap_ResourceBootstrapper</classname>. Dieses
- Interface definiert eine <acronym>API</acronym> für das Erkennen, Registrieren und
- Laden von Ressource-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>
- Ressource-Plugins bieten grundsätzlich die Fähigkeit, Ressource-Initialisierer zu
- erstellen, die zwischen Anwendungen wiederverwendet werden können. Das erlaubt es,
- die aktuelle Bootstrap relativ klein zu halten, und neue Ressourcen einzuführen
- ohne sie in der Bootstrap selbst anzugreifen.
- </para>
- <para>
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> (und bei
- Erweiterung <classname>Zend_Application_Bootstrap_Bootstrap</classname>)
- implementiert dieses Interface genauso, und erlaubt es Ressource-Plugins zu
- verwenden.
- </para>
- <para>
- Um Ressource-Plugins zu verwenden, müssen diese in den Optionen spezifiziert
- werden, die dem Anwendungsobjekt und/oder der Bootstrap übergeben werden. Diese
- Optionen können von einer Konfigurationsdatei kommen, oder manuell übergeben
- werden. Optionen sind Paare von Schlüssel zu Optionen, wobei der Schlüssel
- den Namen der Ressource repräsentiert. Der Ressourcename ist das Segment, das
- dem Klassenpräfix folgt. Die Ressourcen, die zum Beispiel mit Zend Framework
- ausgeliefert werden, haben das Klassenpräfix
- "<classname>Zend_Application_Resource_</classname>"; alles was folgt würde der
- Name der Ressource sein. Als Beispiel:
- </para>
- <programlisting language="php"><![CDATA[
- $application = new Zend_Application(APPLICATION_ENV, array(
- 'resources' => array(
- 'FrontController' => array(
- 'controllerDirectory' => APPLICATION_PATH . '/controllers',
- ),
- ),
- ));
- ]]></programlisting>
- <para>
- Das bedeutet, dass die Ressource "FrontController" verwendet werden sollte, mit den
- spezifizierten Optionen.
- </para>
- <para>
- Wenn man beginnt, eigene Ressource-Plugins zu schreiben, oder Ressource-Plugins von
- dritten anzupassen, muß man der eigenen Bootstrap mitteilen, wo nach ihnen zu suchen
- ist. Intern verwendet Bootstrap <classname>Zend_Loader_PluginLoader</classname>,
- so dass man nur die üblichen Klassenpräfix und Pfadpaare angeben muß.
- </para>
- <para>
- Als Beispiel nehmen wir an, dass wir eigene Ressource-Plugins in
- <filename>APPLICATION_PATH/resources/</filename> haben, und dass sie das gemeinsame
- Klassenpräfix <classname>My_Resource</classname> teilen. Man würde diese
- Information dem Anwendungsobjekt wie folgt übergeben:
- </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>
- Man ist jetzt in der Lage, Ressourcen aus diesem Verzeichnis zu verwenden.
- </para>
- <para>
- Wie Ressource-Methoden kann die Methode <methodname>bootstrap()</methodname>
- verwendet werden, um Ressource-Plugins zu verwenden. Wie bei Ressource-Methoden
- kann man entweder einzelne Ressource-Plugins spezifizieren, mehrere Plugins
- (über ein Array), oder alle Plugins. Zusätzlich kann man mischen und entsprechende
- Ressource-Methoden genauso ausführen.
- </para>
- <programlisting language="php"><![CDATA[
- // Eine ausführen:
- $bootstrap->bootstrap('FrontController');
- // Mehrere ausführen:
- $bootstrap->bootstrap(array('FrontController', 'Foo'));
- // Alle Ressource Methoden und Plugins ausführen:
- $bootstrap->bootstrap();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.application.theory-of-operation.bootstrap.registry">
- <title>Ressource Registry</title>
- <para>
- Viele, wenn nicht sogar alle, der eigenen Ressource-Methoden oder -Plugins
- initialisieren Objekte, und in vielen Fällen werden diese Objekte an anderen
- Orten der Anwendung benötigt. Wie kann man auf sie zugreifen?
- </para>
- <para>
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname>
- bietet eine lokale Registry für diese Objekte. Um eigene Objekte darin zu
- speichern, müssen diese einfach von den eigenen Ressourcen zurückgegeben werden.
- </para>
- <para>
- Für maximale Flexibilität wird diese Registry intern als "Container" bezeichnet;
- die einzige Voraussetzung ist, dass es ein Objekt ist. Ressourcen werden dann als
- Eigenschaften registriert, die nach dem Namen der Ressource benannt sind.
- Standardmäßig wird eine Instanz von <classname>Zend_Registry</classname> verwendet,
- man kann aber jedes andere Objekt spezifizieren, wenn man das will. Die Methoden
- <methodname>setContainer()</methodname> und <methodname>getContainer()</methodname>
- können verwendet werden, um den Container selber zu manipulieren.
- <methodname>getResource($resource)</methodname> kann verwendet werden, um eine
- angegebene Ressource vom Container zu holen, und
- <methodname>hasResource($resource)</methodname> um zu prüfen, ob die Ressource
- aktuell schon registriert wurde.
- </para>
- <para>
- Als Beispiel nehmen wir eine grundlegenden View Ressource an:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initView()
- {
- $view = new Zend_View();
- // weitere Initialisierungen...
- return $view;
- }
- }
- ]]></programlisting>
- <para>
- Man kann sie prüfen und/oder sie wie folgt holen:
- </para>
- <programlisting language="php"><![CDATA[
- // Verwendung der has- und getResource()-Paare:
- if ($bootstrap->hasResource('view')) {
- $view = $bootstrap->getResource('view');
- }
- // Über den Container:
- $container = $bootstrap->getContainer();
- if (isset($container->view)) {
- $view = $container->view;
- }
- ]]></programlisting>
- <para>
- Es ist zu beachten, dass die Registry und auch der Container nicht global sind. Das
- bedeutet, dass man auf die Bootstrap zugreifen muß, um Ressourcen zu holen.
- <classname>Zend_Application_Bootstrap_Bootstrap</classname> bietet einigen
- Komfort hierfür: während der Ausführung von
- <methodname>run()</methodname>, registriert sie sich als FrontController-Parameter
- "bootstrap", was es erlaubt, sie von Routern, Dispatchern, Plugins und
- Action-Controllern zu holen.
- </para>
- <para>
- Wenn man zum Beispiel auf die View Ressource von oben im eigenen Action
- Controller zugreifen will, kann man das wie folgt tun:
- </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>Erkennen von Abhängigkeiten</title>
- <para>
- Zusätzlich zur Ausführung von Ressource-Methoden und -Plugins, ist es notwendig
- sicherzustellen, dass diese einmal und wirklich nur einmal ausgeführt werden; sie
- sollen eine Anwendung bootstrappen, und die mehrfache Ausführung von ihnen kann
- zu einem Overhead von Ressourcen führen.
- </para>
- <para>
- Zur gleichen Zeit können Ressourcen von anderen ausgeführten Ressourcen abhängen.
- Um diese zwei Fälle zu lösen bietet
- <classname>Zend_Application_Bootstrap_BootstrapAbstract</classname> einen einfachen
- und effektiven Mechanismus für die Erkennung von Abhängigkeiten.
- </para>
- <para>
- Wie vorher erwähnt werden alle Ressourcen -- ob Methoden oder Plugins -- durch den
- Aufruf von <methodname>bootstrap($resource)</methodname> gebootstrappt, wobei
- <varname>$resource</varname> der Name einer Ressource ist, ein Array von Ressourcen
- oder leer gelassen wird, was zeigt, dass alle Ressourcen ausgeführt werden sollen.
- </para>
- <para>
- Wenn eine Ressource von anderen Ressourcen abhängig ist, sollten Sie in Ihrem Code
- <methodname>bootstrap()</methodname> aufrufen um sicherzustellen, dass die Ressource
- ausgeführt wurde. Weitere Aufrufe von ihr werden dann ignoriert.
- </para>
- <para>
- In einer Ressource-Methode würde so ein Aufruf wie folgt aussehen:
- </para>
- <programlisting language="php"><![CDATA[
- class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
- {
- protected function _initRequest()
- {
- // Sicherstellen, dass der FrontController initialisiert wird
- $this->bootstrap('FrontController');
- // Den FrontController von der Bootstrap Registry erhalten
- $front = $this->getResource('FrontController');
- $request = new Zend_Controller_Request_Http();
- $request->setBaseUrl('/foo');
- $front->setRequest($request);
- // Sicherstellen, dass die Anfrage in der Bootstrap Registry
- // gespeichert ist
- return $request;
- }
- }
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="zend.application.theory-of-operation.resources">
- <title>Ressource Plugins</title>
- <para>
- <link linkend="zend.application.theory-of-operation.bootstrap.resource-plugins">Wie
- vorher erwähnt</link> ist die Verwendung von Ressource Plugins ein guter Weg, um
- wiederverwendbare Bootstrap-Ressourcen zu erstellen und um so viel eigenen Code wie
- möglich in diskrete Klassen auszulagern. Wärend Zend Framework mit einer Anzahl
- von standardmäßigen Ressource-Plugins geliefert wird, besteht das Ziel darin, dass der
- Entwickler eigene schreiben sollte, um seine eigenen Notwendigkeiten der
- Initialisierung zu kapseln.
- </para>
- <para>
- Ressource-Plugins müssen nur <classname>Zend_Application_Resource_Resource</classname>
- implementieren, oder einfach
- <classname>Zend_Application_Resource_ResourceAbstract</classname> erweitern. Das
- grundsätzliche Interface ist folgendes:
- </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>
- Das Interface definiert einfach, was ein Ressouce-Plugin an Optionen im Konstruktor
- akzeptieren sollte, die Mechanismen für das Setzen und Zurückgeben von Optionen,
- die Mechanismen für das Setzen und Zurückgeben des Bootstrap-Objekts und eine
- Initialisierungs-Methode.
- </para>
- <para>
- Als Beispiel nehmen wir an, dass wir eine normale View Initialisierung haben, die in der
- eigenen Anwendung verwendet wird. Man hat normale Doctype, <acronym>CSS</acronym> und
- Javascript, und will in der Lage sein, diese in einem Standard-Dokumententitel über die
- Konfiguration zu übergeben. So ein Ressource-Plugin könnte wie folgt aussehen:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
- {
- protected $_view;
- public function init()
- {
- // Die View zurückgeben damit die Bootstrap sie
- // in der Registry speichert
- 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>
- Solange man den Präfix-Pfad für dieses Ressource-Plugin registriert, kann es in der
- eigenen Anwendung verwendet werden. Weil der Plugin-Loader verwendet wird, ist es
- besser, das gelieferte "View"-Ressource-Plugin zu überschreiben und sicherzustellen,
- dass man stattdessen das eigene verwendet.
- </para>
- </sect2>
- </sect1>
|