| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.tool.framework.writing-providers">
- <title>Erstellen von Providern für die Verwendung mit Zend_Tool_Framework</title>
- <para>
- Generell ist ein Provider für sich selbst nichts mehr als die Shell für einen Entwickler
- um einige Fähigkeiten zu bündeln die man mit dem Kommandozeilen (oder einem anderen)
- Client ausliefern will. Das ist analog zu dem was ein "Controller" in einer
- <acronym>MVC</acronym> Anwendung ist.
- </para>
- <sect2 id="zend.tool.framework.writing-providers.loading">
- <title>Wie Zend_Tool eigene Provider findet</title>
- <para>
- Standardmäßig verwendet <classname>Zend_Tool</classname> den IncludePathLoader um alle
- Provider zu finden die man ausführen kann. Er iteriert rekursiv alle Verzeichnisse des
- Include Pfads und öffnet alle Dateien die mit "Manifest.php" oder "Provider.php" enden.
- Alle Klassen in diesen Dateien werden angeschaut ob Sie entweder
- <classname>Zend_Tool_Framework_Provider_Interface</classname> oder
- <classname>Zend_Tool_Framework_Manifest_ProviderManifestable</classname> implementieren.
- Instanzen des Provider Interfaces machen die wirkliche Funtionalität aus und auf alle
- Ihre öffentlichen Methoden kann man als Provider Aktionen zugreifen. Das Interface
- ProviderManifestable benötigt trotzdem eine Implementation einer
- <methodname>getProviders()</methodname> Methode welche ein Array der instanziierten
- Provider Interface Instanzen zurückgibt.
- </para>
- <para>
- Die folgenden Namensregeln zeigen wir man auf die Provider zugreifen kann die vom
- IncludePathLoader gefunden wurden:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Der letzte Teil des Klassennamens der durch einen Unterstrich geteilt wird,
- wird für den Provider Namen verwendet, z.B. führt "My_Provider_Hello" dazu dass
- auf den eigenen Provider mit dem Namen "hello" zugegriffen werden kann.
- </para>
- </listitem>
- <listitem>
- <para>
- Wenn der eigene Provider eine <methodname>getName()</methodname> Methode hat,
- wird diese statt der vorhergehenden Methode verwendet um den Namen zu erkennen.
- </para>
- </listitem>
- <listitem>
- <para>
- Wenn der eigene Provider "Provider" als Präfix hat, er z.B.
- <classname>My_HelloProvider</classname> genannt wird, dann wird dieser vom
- Namen entfernt sodass der Provider "hello" genannt wird.
- </para>
- </listitem>
- </itemizedlist>
- <note>
- <para>
- Der IncludePathLoader folgt Symlinks nicht, was bedeutet das man Provider
- Funktionalitäten nicht im eigenen Include Pfad verlinken kann, da diese physikalisch
- im Include Pfad vorhanden sein müssen.
- </para>
- </note>
- <example id="zend.tool.framework.writing-providers.loading.example">
- <title>Eigene Provider mit einem Manifest bekanntmachen</title>
- <para>
- Man kann eigene Provider bei <classname>Zend_Tool</classname> bekannt machen indem
- man ein Manifest mit einem speziellen Dateinamen anbietet der mit "Manifest.php"
- endet. Ein Provider Manifest ist eine Implementation von
- <interface>Zend_Tool_Framework_Manifest_ProviderManifestable</interface> und
- benötigt die Methode <methodname>getProviders()</methodname> welche ein Array von
- instanziierten Providern zurückgibt. Anders als unser erster eigener Provider
- erstellt <classname>My_Component_HelloProvider</classname> das folgende Manifest:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_Manifest
- implements Zend_Tool_Framework_Manifest_ProviderManifestable
- {
- public function getProviders()
- {
- return array(
- new My_Component_HelloProvider()
- );
- }
- }
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.basic">
- <title>Grundsätzliche Anweisungen für die Erstellung von Providern</title>
- <para>
- Wenn, als Beispiel, ein Entwickler die Fähigkeit hinzufügen will, die Version einer
- Datendatei anzuzeigen, mit der seine 3rd Party Komponente arbeitet, gibt es nur eine
- Klasse die der Entwickler implementieren muss. Angenommen die Komponente heisst
- <classname>My_Component</classname>, dann würde er eine Klasse erstellen die
- <classname>My_Component_HelloProvider</classname> heisst und in einer Datei ist die
- <filename>HelloProvider.php</filename> heisst und irgendwo im
- <property>include_path</property> ist. Diese Klasse würde
- <classname>Zend_Tool_Framework_Provider_Interface</classname> implementieren, und der
- Body dieser Datei würde nur wie folgt auszusehen haben:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say()
- {
- echo 'Hallo von meinem Provider!';
- }
- }
- ]]></programlisting>
- <para>
- Durch den obigen Code, und der Annahme das der Entwickler den Zugriff auf diese
- funktionalität über den Consolen Client will, würde der Aufruf wie folgt aussehen:
- </para>
- <programlisting language="sh"><![CDATA[
- % zf say hello
- Hello from my provider!
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.response">
- <title>Das Antwort Objekt</title>
- <para>
- Wie in der Archikektur Sektion diskutiert erlaubt <classname>Zend_Tool</classname>
- unterschiedliche Clients für die Verwendung in <classname>Zend_Tool</classname>
- Providern zu verwenden. Um mit den unterschiedlichen Clients kompatibel zu bleiben
- sollte man das Antwort Objekt verwenden um Nachrichten von eigenen Providern
- zurückzugeben, statt <methodname>echo()</methodname> oder ähnliche Ausgabe Mechanismen
- zu verwenden. Unser umgeschriebener Hallo Provider sieht mit dem jetzt bekannten wie
- folgt aus:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $this->_registry->getResponse
- ->appendContent("Hello from my provider!");
- }
- }
- ]]></programlisting>
- <para>
- Wie man sieht muss man <classname>Zend_Tool_Framework_Provider_Abstract</classname>
- erweitern um Zugriff auf die Registry zu erhalten, welche die Instanz von
- <classname>Zend_Tool_Framework_Client_Response</classname> hält.
- </para>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.advanced">
- <title>Fortgeschrittene Informationen für die Entwicklung</title>
- <sect3 id="zend.tool.framework.writing-providers.advanced.variables">
- <title>Variablen an einen Provider übergeben</title>
- <para>
- Das obige "Hello World" Beispiel ist perfekt für einfache Kommandos, aber was ist
- mit etwas fortgeschrittenerem? Wenn das Scripting und Tooling wächst, kann die
- Notwendigkeit entstehen Variablen zu akzeptieren. So wie Signaturen von Funktionen
- Parameter haben, kann eine Tooling Anfrage auch Parameter akzeptieren.
- </para>
- <para>
- So wie jede Tooling Anfrage in einer Methode in einer Klasse isoliert werden kann,
- können die Parameter einer Tooling Anfrage auch in einem sehr bekannten Platz
- isoliert werden. Parameter von Action Methoden eines Providers können die selben
- Parameter enthalten die man im Client verwenden will, wenn man den Namen im obigen
- Beispiel akzeptieren will, und man würde das in OO Code warscheinlich wie folgt tun:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say($name = 'Ralph')
- {
- echo 'Hallo' . $name . ', von meinem Provider!';
- }
- }
- ]]></programlisting>
- <para>
- Das obige Beispiel kann über die Kommandozeile wie folgt aufgerufen werden:
- <command>zf say hello Joe</command>. "Joe" wird dem Provider als Parameter des
- Methodenaufrufs zur Verfügung gestellt. Es ist auch zu beachten das der Parameter
- optional ist, was bedeutet das er auch auf der Kommandozeile optional ist, so das
- <command>zf say hello</command> weiterhin funktioniert, und der Standardname "Ralph"
- ist.
- </para>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.prompt">
- <title>Den Benutzer nach einer Eingabe fragen</title>
- <para>
- Es gibt Fälle in denen der Workflow des Providers es notwendig macht, den Benutzer
- nach einer Eingabe zu fragen. Das kann getan werden, indem der Client angewiesen
- wird nach der benötigten Eingabe zu Fragen, indem man folgendes aufruft:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say($name = 'Ralph')
- {
- $nameResponse = $this->_registry
- ->getClient()
- ->promptInteractiveInput("Wie ist dein Name?");
- $name = $nameResponse->getContent();
- echo 'Hallo' . $name . ', von meinem Provider!';
- }
- }
- ]]></programlisting>
- <para>
- Dieses Kommando wirft eine Exception wenn der aktuelle Client nicht in der Lage ist
- die Interaktive Anfrage zu behandeln. Im Fall des standardmäßigen Konsolen Clients
- wird man trotzdem danach gefragt den Namen einzugeben.
- </para>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.pretendable">
- <title>Voranstellen um eine Provider Aktion auszuführen</title>
- <para>
- Ein anderes interessantes Feature das man implementieren kann ist
- <emphasis>Voranstellbarkeit</emphasis>. Voranstellbarkeit ist die Fähigkeit des
- Providers "Voranzustellen" wie wenn er die angefragte Aktion und Provider
- Kombination ausführt, und dem Benutzer so viel Information wie möglich darüber gibt
- was er tun <emphasis>würde</emphasis> ohne es wirklich zu tun. Das kann eine
- wichtige Option sein wenn viele Datenbank oder Dateisystem Änderungen durchzuführen
- sind, die der Benutzer andernfalls nicht tun würde.
- </para>
- <para>
- Voranstellbarkeit ist einfach zu implementieren. Es gibt zwei Teile dieses Features:
- 1) Markieren des Providers, das er die Fähigkeit des "voranstellens" hat und 2)
- prüfen der Anfrage um Sicherzustellen das die aktuelle Anfrage wirklich das
- "voranstellen" angefragt hat. Dieses Feature wird im nächsten Code Beispiel
- demonstriert.
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- implements Zend_Tool_Framework_Provider_Pretendable
- {
- public function say($name = 'Ralph')
- {
- if ($this->_registry->getRequest()->isPretend()) {
- echo 'Ich würde zu ' . $name . ' hallo sagen.';
- } else {
- echo 'Hallo' . $name . ', von meinem Provider!';
- }
- }
- }
- ]]></programlisting>
- <para>
- Um den Provider im vorangestellten Modus auszuführen muss folgendes aufgerufen
- werden:
- </para>
- <programlisting language="sh"><![CDATA[
- % zf --pretend say hello Ralph
- I würde zu Ralph hallo sagen.
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.verbosedebug">
- <title>Verbose und Debug Modi</title>
- <para>
- Man kann Provider Aktionen auch im "verbose" oder "debug" Modus ausführen. Die
- Semantik in Bezug zu diesen Aktionen muss man selbst im Kontext des eigenen
- Providers implementieren. Man kann auf die Debug und Verbose Modi wie folgt
- zugreifen:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say($name = 'Ralph')
- {
- if($this->_registry->getRequest()->isVerbose()) {
- echo "Hello::say wurde aufgerufen\n";
- }
- if($this->_registry->getRequest()->isDebug()) {
- syslog(LOG_INFO, "Hello::say wurde aufgerufen\n");
- }
- }
- }
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.configstorage">
- <title>Zugriff auf Benutzer Konfiguration und Speicher</title>
- <para>
- Wenn man die Umgebungsvariable <property>ZF_CONFIG_FILE</property> oder
- .zf.ini im Home Verzeichnis verwendet kann man Konfigurationsparameter in jedem
- <classname>Zend_Tool</classname> Provider injizieren. Zugriff auf diese
- Konfiguration ist über die Registry möglich die dem Provider übergeben wird, wenn
- man <classname>Zend_Tool_Framework_Provider_Abstract</classname> erweitert.
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $username = $this->_registry->getConfig()->username;
- if(!empty($username)) {
- echo "Hallo $username!";
- } else {
- echo "Hallo!";
- }
- }
- }
- ]]></programlisting>
- <para>
- Die zurückgegebene Konfiguration ist vom Typ
- <classname>Zend_Tool_Framework_Client_Config</classname>, aber intern verweisen die
- magischen Methoden <methodname>__get()</methodname> und
- <methodname>__set()</methodname> auf <classname>Zend_Config</classname> des
- angegebenen Konfigurations Typs.
- </para>
- <para>
- Der Speicher erlaubt es eigene Daten für eine spätere Referenz zu speichern. Das
- kann für Batch Aufgaben oder für ein erneutes Ausführen von Tasks nützlich sein. Man
- kann auf den Speicher auf eine ähnliche Art und Weise zugreifen wie auf die
- Konfiguration:
- </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $aValue = $this->_registry->getStorage()->get("myUsername");
- echo "Hallo $aValue!";
- }
- }
- ]]></programlisting>
- <para>
- Die <acronym>API</acronym> des Speichers ist sehr einfach:
- </para>
- <programlisting language="php"><![CDATA[
- class Zend_Tool_Framework_Client_Storage
- {
- public function setAdapter($adapter);
- public function isEnabled();
- public function put($name, $value);
- public function get($name, $defaultValue=null);
- public function has($name);
- public function remove($name);
- public function getStreamUri($name);
- }
- ]]></programlisting>
- <important>
- <para>
- Wenn man eigene Provider designt die auf Konfguration oder Speicher rücksicht
- nehmen sollte man darauf achten ob die benötigten Benutzer-Konfigurations oder
- Speicher Schlüssel bereits für einen Benutzer existieren. Man würde keine
- fatalen Fehler erhalten wenn keine von ihnen angegeben werden, da leere
- Schlüssel bei der Anfrage erstellt werden.
- </para>
- </important>
- </sect3>
- </sect2>
- </sect1>
|