2
0

Zend_Tool_Framework-WritingProviders.xml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 18033 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.tool.framework.writing-providers">
  5. <title>Erstellen von Providern für die Verwendung mit Zend_Tool_Framework</title>
  6. <para>
  7. Generell ist ein Provider für sich selbst nichts mehr als die Shell für einen Entwickler
  8. um einige Fähigkeiten zu bündeln die man mit dem Kommandozeilen (oder einem anderen)
  9. Client ausliefern will. Das ist analog zu dem was ein "Controller" in einer
  10. <acronym>MVC</acronym> Anwendung ist.
  11. </para>
  12. <sect2 id="zend.tool.framework.writing-providers.manifest">
  13. <title>Eigene Provider mit einem Manifest bekanntmachen</title>
  14. <para>
  15. Bevor man eigene Provider schreibt muss man ein Manifest erstellen, welches Instanzen
  16. der eigenen Provider zurückgibt, um es Zend Tool zu erlauben diese zu erkennen. Ein
  17. Provider Manifest ist eine Implementation von
  18. <interface>Zend_Tool_Framework_Manifest_ProviderManifestable</interface> und benötigt
  19. die Methode <code>getProviders()</code> welche ein Array von initialisierten Providern
  20. zurückgibt. Im gegensatz zu unserem ersten eigenen Provider
  21. <classname>My_Component_HelloProvider</classname> erstellen wir das folgende Manifest:
  22. </para>
  23. <programlisting language="php"><![CDATA[
  24. class My_Component_Manifest implements Zend_Tool_Framework_Manifest_ProviderManifestable
  25. {
  26. public function getProviders()
  27. {
  28. return array(
  29. new My_Component_HelloProvider()
  30. );
  31. }
  32. }
  33. ]]>
  34. </programlisting>
  35. <para>
  36. Eine Provider Manifest Klasse muss immer mit dem Term "Manifest" enden, andernfalls
  37. kann Sie Zend_Tool nicht automatisch erkennen wenn es den Include Pfad durchsucht.
  38. </para>
  39. </sect2>
  40. <sect2 id="zend.tool.framework.writing-providers.basic">
  41. <title>Grundsätzliche Anweisungen für die Erstellung von Providern</title>
  42. <para>
  43. Wenn, als Beispiel, ein Entwickler die Fähigkeit hinzufügen will, die Version einer
  44. Datendatei anzuzeigen, mit der seine 3rd Party Komponente arbeitet, gibt es nur eine
  45. Klasse die der Entwickler implementieren muss. Angenommen die Komponente heisst
  46. <classname>My_Component</classname>, dann würde er eine Klasse erstellen die
  47. <classname>My_Component_HelloProvider</classname> heisst und in einer Datei ist die
  48. <filename>HelloProvider.php</filename> heisst und irgendwo im
  49. <property>include_path</property> ist. Diese Klasse würde
  50. <classname>Zend_Tool_Framework_Provider_Interface</classname> implementieren, und der
  51. Body dieser Datei würde nur wie folgt auszusehen haben:
  52. </para>
  53. <programlisting language="php"><![CDATA[
  54. class My_Component_HelloProvider
  55. implements Zend_Tool_Framework_Provider_Interface
  56. {
  57. public function say()
  58. {
  59. echo 'Hallo von meinem Provider!';
  60. }
  61. }
  62. ]]></programlisting>
  63. <para>
  64. Durch den obigen Code, und der Annahme das der Entwickler den Zugriff auf diese
  65. funktionalität über den Consolen Client will, würde der Aufruf wie folgt aussehen:
  66. </para>
  67. <programlisting language="sh"><![CDATA[
  68. % zf say hello
  69. Hello from my provider!
  70. ]]></programlisting>
  71. </sect2>
  72. <sect2 id="zend.tool.framework.writing-providers.response">
  73. <title>Das Antwort Objekt</title>
  74. <para>
  75. Wie in der Archikektur Sektion diskutiert erlaubt Zend Tool unterschiedliche Clients für
  76. die Verwendung in Zend Tool Providern zu verwenden. Um mit den unterschiedlichen Clients
  77. kompatibel zu bleiben sollte man das Antwort Objekt verwenden um Nachrichten von eigenen
  78. Providern zurückzugeben, statt <code>echo</code> oder ähnliche Ausgabe Mechanismen zu
  79. verwenden. Unser umgeschriebener Hallo Provider sieht mit dem jetzt bekannten wie folgt
  80. aus:
  81. </para>
  82. <programlisting language="php"><![CDATA[
  83. class My_Component_HelloProvider
  84. extends Zend_Tool_Framework_Provider_Abstract
  85. {
  86. public function say()
  87. {
  88. $this->_registry->getResponse()->appendContent("Hello from my provider!");
  89. }
  90. }
  91. ]]>
  92. </programlisting>
  93. <para>
  94. Wie man sieht muss man <classname>Zend_Tool_Framework_Provider_Abstract</classname>
  95. erweitern um Zugriff auf die Registry zu erhalten, welche die Instanz von
  96. <classname>Zend_Tool_Framework_Client_Response</classname> hält.
  97. </para>
  98. </sect2>
  99. <sect2 id="zend.tool.framework.writing-providers.advanced">
  100. <title>Fortgeschrittene Informationen für die Entwicklung</title>
  101. <sect3 id="zend.tool.framework.writing-providers.advanced.variables">
  102. <title>Variablen an einen Provider übergeben</title>
  103. <para>
  104. Das obige "Hello World" Beispiel ist perfekt für einfache Kommandos, aber was ist
  105. mit etwas fortgeschrittenerem? Wenn das Scripting und Tooling wächst, kann die
  106. Notwendigkeit entstehen Variablen zu akzeptieren. So wie Signaturen von Funktionen
  107. Parameter haben, kann eine Tooling Anfrage auch Parameter akzeptieren.
  108. </para>
  109. <para>
  110. So wie jede Tooling Anfrage in einer Methode in einer Klasse isoliert werden kann,
  111. können die Parameter einer Tooling Anfrage auch in einem sehr bekannten Platz
  112. isoliert werden. Parameter von Action Methoden eines Providers können die selben
  113. Parameter enthalten die man im Client verwenden will, wenn man den Namen im obigen
  114. Beispiel akzeptieren will, und man würde das in OO Code warscheinlich wie folgt tun:
  115. </para>
  116. <programlisting language="php"><![CDATA[
  117. class My_Component_HelloProvider
  118. implements Zend_Tool_Framework_Provider_Interface
  119. {
  120. public function say($name = 'Ralph')
  121. {
  122. echo 'Hallo' . $name . ', von meinem Provider!';
  123. }
  124. }
  125. ]]></programlisting>
  126. <para>
  127. Das obige Beispiel kann über die Kommandozeile wie folgt aufgerufen werden:
  128. <command>zf say hello Joe</command>. "Joe" wird dem Provider als Parameter des
  129. Methodenaufrufs zur Verfügung gestellt. Es ist auch zu beachten das der Parameter
  130. optional ist, was bedeutet das er auch auf der Kommandozeile optional ist, so das
  131. <command>zf say hello</command> weiterhin funktioniert, und der Standardname "Ralph"
  132. ist.
  133. </para>
  134. </sect3>
  135. <sect3 id="zend.tool.framework.writing-providers.advanced.prompt">
  136. <title>Den Benutzer nach einer Eingabe fragen</title>
  137. <para>
  138. Es gibt Fälle in denen der Workflow des Providers es notwendig macht, den Benutzer
  139. nach einer Eingabe zu fragen. Das kann getan werden, indem der Client angewiesen
  140. wird nach der benötigten Eingabe zu Fragen, indem man folgendes aufruft:
  141. </para>
  142. <programlisting language="php"><![CDATA[
  143. class My_Component_HelloProvider
  144. extends Zend_Tool_Framework_Provider_Abstract
  145. {
  146. public function say($name = 'Ralph')
  147. {
  148. $nameResponse = $this->_registry->getClient()->promptInteractiveInput("Wie ist dein Name?");
  149. $name = $name->getContent();
  150. echo 'Hallo' . $name . ', von meinem Provider!';
  151. }
  152. }
  153. ]]>
  154. </programlisting>
  155. <para>
  156. Dieses Kommando wirft eine Exception wenn der aktuelle Client nicht in der Lage ist
  157. die Interaktive Anfrage zu behandeln. Im Fall des standardmäßigen Konsolen Clients
  158. wird man trotzdem danach gefragt den Namen einzugeben.
  159. </para>
  160. </sect3>
  161. <sect3 id="zend.tool.framework.writing-providers.advanced.pretendable">
  162. <title>Voranstellen um eine Provider Aktion auszuführen</title>
  163. <para>
  164. Ein anderes interessantes Feature das man implementieren kann ist
  165. <emphasis>Voranstellbarkeit</emphasis>. Voranstellbarkeit ist die Fähigkeit des
  166. Providers "Voranzustellen" wie wenn er die angefragte Aktion und Provider
  167. Kombination ausführt, und dem Benutzer so viel Information wie möglich darüber gibt
  168. was er tun <emphasis>würde</emphasis> ohne es wirklich zu tun. Das kann eine wichtige
  169. Option sein wenn viele Datenbank oder Dateisystem Änderungen durchzuführen sind, die
  170. der Benutzer andernfalls nicht tun würde.
  171. </para>
  172. <para>
  173. Voranstellbarkeit ist einfach zu implementieren. Es gibt zwei Teile dieses Features:
  174. 1) Markieren des Providers, das er die Fähigkeit des "voranstellens" hat und 2) prüfen
  175. der Anfrage um Sicherzustellen das die aktuelle Anfrage wirklich das "voranstellen"
  176. angefragt hat. Dieses Feature wird im nächsten Code Beispiel demonstriert.
  177. </para>
  178. <programlisting language="php"><![CDATA[
  179. class My_Component_HelloProvider
  180. extends Zend_Tool_Framework_Provider_Abstract
  181. implements Zend_Tool_Framework_Provider_Pretendable
  182. {
  183. public function say($name = 'Ralph')
  184. {
  185. if ($this->_registry->getRequest()->isPretend()) {
  186. echo 'Ich würde zu ' . $name . ' hallo sagen.';
  187. } else {
  188. echo 'Hallo' . $name . ', von meinem Provider!';
  189. }
  190. }
  191. }
  192. ]]></programlisting>
  193. <para>
  194. Um den Provider im vorangestellten Modus auszuführen muss folgendes aufgerufen
  195. werden:
  196. </para>
  197. <programlisting language="sh"><![CDATA[
  198. % zf --pretend say hello Ralph
  199. I würde zu Ralph hallo sagen.
  200. ]]></programlisting>
  201. </sect3>
  202. <sect3 id="zend.tool.framework.writing-providers.advanced.verbosedebug">
  203. <title>Verbose und Debug Modi</title>
  204. <para>
  205. Man kann Provider Aktionen auch im "verbose" oder "debug" Modus ausführen. Die
  206. Semantik in Bezug zu diesen Aktionen muss man selbst im Kontext des eigenen
  207. Providers implementieren. Man kann auf die Debug und Verbose Modi wie folgt
  208. zugreifen:
  209. </para>
  210. <programlisting language="php"><![CDATA[
  211. class My_Component_HelloProvider
  212. implements Zend_Tool_Framework_Provider_Interface
  213. {
  214. public function say($name = 'Ralph')
  215. {
  216. if($this->_registry->getRequest()->isVerbose()) {
  217. echo "Hello::say wurde aufgerufen\n";
  218. }
  219. if($this->_registry->getRequest()->isDebug()) {
  220. syslog(LOG_INFO, "Hello::say wurde aufgerufen\n");
  221. }
  222. }
  223. }
  224. ]]></programlisting>
  225. </sect3>
  226. <sect3 id="zend.tool.framework.writing-providers.advanced.configstorage">
  227. <title>Zugriff auf Benutzer Konfiguration und Speicher</title>
  228. <para>
  229. Wenn man die Umgebungsvariable <property>ZF_CONFIG_FILE</property> oder
  230. .zf.ini im Home Verzeichnis verwendet kann man Konfigurationsparameter in jedem
  231. Zend Tool Provider injizieren. Zugriff auf diese Konfiguration ist über die
  232. Registry möglich die dem Provider übergeben wird, wenn man
  233. <classname>Zend_Tool_Framework_Provider_Abstract</classname> erweitert.
  234. </para>
  235. <programlisting language="php"><![CDATA[
  236. class My_Component_HelloProvider
  237. extends Zend_Tool_Framework_Provider_Abstract
  238. {
  239. public function say()
  240. {
  241. $username = $this->_registry->getConfig()->username;
  242. if(!empty($username)) {
  243. echo "Hallo $username!";
  244. } else {
  245. echo "Hallo!";
  246. }
  247. }
  248. }
  249. ]]></programlisting>
  250. <para>
  251. Die zurückgegebene Konfiguration ist vom Typ
  252. <classname>Zend_Tool_Framework_Client_Config</classname>, aber intern verweisen die
  253. magischen Methoden <code>__get</code> und <code>__set</code> auf
  254. <classname>Zend_Config</classname> des angegebenen Konfigurations Typs.
  255. </para>
  256. <para>
  257. Der Speicher erlaubt es eigene Daten für eine spätere Referenz zu speichern. Das
  258. kann für Batch Aufgaben oder für ein erneutes Ausführen von Tasks nützlich sein. Man
  259. kann auf den Speicher auf eine ähnliche Art und Weise zugreifen wie auf die
  260. Konfiguration:
  261. </para>
  262. <programlisting language="php"><![CDATA[
  263. class My_Component_HelloProvider
  264. extends Zend_Tool_Framework_Provider_Abstract
  265. {
  266. public function say()
  267. {
  268. $aValue = $this->_registry->getStorage()->get("myUsername");
  269. echo "Hallo $aValue!";
  270. }
  271. }
  272. ]]>
  273. </programlisting>
  274. <para>
  275. Die API des Speichers ist sehr einfach:
  276. </para>
  277. <programlisting language="php"><![CDATA[
  278. class Zend_Tool_Framework_Client_Storage
  279. {
  280. public function setAdapter($adapter);
  281. public function isEnabled();
  282. public function put($name, $value);
  283. public function get($name, $defaultValue=null);
  284. public function has($name);
  285. public function remove($name);
  286. public function getStreamUri($name);
  287. }
  288. ]]>
  289. </programlisting>
  290. <important>
  291. <para>
  292. Wenn man eigene Provider designt die auf Konfguration oder Speicher rücksicht
  293. nehmen sollte man darauf achten ob die benötigten Benutzer-Konfigurations oder
  294. Speicher Schlüssel bereits für einen Benutzer existieren. Man würde keine
  295. fatalen Fehler erhalten wenn keine von ihnen angegeben werden, da leere
  296. Schlüssel bei der Anfrage erstellt werden.
  297. </para>
  298. </important>
  299. </sect3>
  300. </sect2>
  301. </sect1>