Zend_Tool_Framework-WritingProviders.xml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 18011 -->
  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>Dem Benutzer eine Eingabe anzeigen</title>
  137. <para>
  138. Es gibt Fälle in denen der Workflow des eigenen Providers es erfordert, dass dem
  139. Benutzer eine Eingabe angezeigt wird. Das kann getan werden indem der Client
  140. angewiesen wird nach weiteren benötigen Eingaben zu fragen indem folgendes
  141. aufgerufen wird:
  142. </para>
  143. <programlisting language="php"><![CDATA[
  144. class My_Component_HelloProvider
  145. extends Zend_Tool_Framework_Provider_Abstract
  146. {
  147. public function say($name = 'Ralph')
  148. {
  149. $nameResponse = $this->_registry->getClient()->promptInteractiveInput("Wie ist dein Name?");
  150. $name = $name->getContent();
  151. echo 'Hallo ' . $name . ', von meinem Provider!';
  152. }
  153. }
  154. ]]>
  155. </programlisting>
  156. <para>
  157. Dieses Kommando wirft eine Exception wenn der aktuelle Client nicht in der Lage ist
  158. interaktive Anfragen zu behandeln. Im Fall des standardmäßigen Konsolen Clients
  159. wird man gefragt den Namen einzugeben.
  160. </para>
  161. </sect3>
  162. <sect3 id="zend.tool.framework.writing-providers.advanced.pretendable">
  163. <title>Voranstellen um eine Provider Aktion auszuführen</title>
  164. <para>
  165. Ein anderes interessantes Feature das man implementieren kann ist
  166. <emphasis>Voranstellbarkeit</emphasis>. Voranstellbarkeit ist die Fähigkeit des
  167. Providers "Voranzustellen" wie wenn er die angefragte Aktion und Provider
  168. Kombination ausführt, und dem Benutzer so viel Information wie möglich darüber gibt
  169. was er tun <emphasis>würde</emphasis> ohne es wirklich zu tun. Das kann eine wichtige
  170. Option sein wenn viele Datenbank oder Dateisystem Änderungen durchzuführen sind, die
  171. der Benutzer andernfalls nicht tun würde.
  172. </para>
  173. <para>
  174. Voranstellbarkeit ist einfach zu implementieren. Es gibt zwei Teile dieses Features:
  175. 1) Markieren des Providers, das er die Fähigkeit des "voranstellens" hat und 2) prüfen
  176. der Anfrage um Sicherzustellen das die aktuelle Anfrage wirklich das "voranstellen"
  177. angefragt hat. Dieses Feature wird im nächsten Code Beispiel demonstriert.
  178. </para>
  179. <programlisting language="php"><![CDATA[
  180. class My_Component_HelloProvider
  181. extends Zend_Tool_Framework_Provider_Abstract
  182. implements Zend_Tool_Framework_Provider_Pretendable
  183. {
  184. public function say($name = 'Ralph')
  185. {
  186. if ($this->_registry->getRequest()->isPretend()) {
  187. echo 'Ich würde zu ' . $name . ' hallo sagen.';
  188. } else {
  189. echo 'Hallo' . $name . ', von meinem Provider!';
  190. }
  191. }
  192. }
  193. ]]></programlisting>
  194. <para>
  195. Um den Provider im vorangestellten Modus auszuführen muss folgendes aufgerufen
  196. werden:
  197. </para>
  198. <programlisting language="sh"><![CDATA[
  199. % zf --pretend say hello Ralph
  200. I würde zu Ralph hallo sagen.
  201. ]]></programlisting>
  202. </sect3>
  203. <sect3 id="zend.tool.framework.writing-providers.advanced.verbosedebug">
  204. <title>Verbose und Debug Modi</title>
  205. <para>
  206. Man kann Provider Aktionen auch im "verbose" oder "debug" Modus ausführen. Die
  207. Semantik in Bezug zu diesen Aktionen muss man selbst im Kontext des eigenen
  208. Providers implementieren. Man kann auf die Debug und Verbose Modi wie folgt
  209. zugreifen:
  210. </para>
  211. <programlisting language="php"><![CDATA[
  212. class My_Component_HelloProvider
  213. implements Zend_Tool_Framework_Provider_Interface
  214. {
  215. public function say($name = 'Ralph')
  216. {
  217. if($this->_registry->getRequest()->isVerbose()) {
  218. echo "Hello::say wurde aufgerufen\n";
  219. }
  220. if($this->_registry->getRequest()->isDebug()) {
  221. syslog(LOG_INFO, "Hello::say wurde aufgerufen\n");
  222. }
  223. }
  224. }
  225. ]]></programlisting>
  226. </sect3>
  227. <sect3 id="zend.tool.framework.writing-providers.advanced.configstorage">
  228. <title>Zugriff auf Benutzer Konfiguration und Speicher</title>
  229. <para>
  230. Wenn man die Umgebungsvariable <property>ZF_CONFIG_FILE</property> oder
  231. .zf.ini im Home Verzeichnis verwendet kann man Konfigurationsparameter in jedem
  232. Zend Tool Provider injizieren. Zugriff auf diese Konfiguration ist über die
  233. Registry möglich die dem Provider übergeben wird, wenn man
  234. <classname>Zend_Tool_Framework_Provider_Abstract</classname> erweitert.
  235. </para>
  236. <programlisting language="php"><![CDATA[
  237. class My_Component_HelloProvider
  238. extends Zend_Tool_Framework_Provider_Abstract
  239. {
  240. public function say()
  241. {
  242. $username = $this->_registry->getConfig()->username;
  243. if(!empty($username)) {
  244. echo "Hallo $username!";
  245. } else {
  246. echo "Hallo!";
  247. }
  248. }
  249. }
  250. ]]></programlisting>
  251. <para>
  252. Die zurückgegebene Konfiguration ist vom Typ
  253. <classname>Zend_Tool_Framework_Client_Config</classname>, aber intern verweisen die
  254. magischen Methoden <code>__get</code> und <code>__set</code> auf
  255. <classname>Zend_Config</classname> des angegebenen Konfigurations Typs.
  256. </para>
  257. <para>
  258. Der Speicher erlaubt es eigene Daten für eine spätere Referenz zu speichern. Das
  259. kann für Batch Aufgaben oder für ein erneutes Ausführen von Tasks nützlich sein. Man
  260. kann auf den Speicher auf eine ähnliche Art und Weise zugreifen wie auf die
  261. Konfiguration:
  262. </para>
  263. <programlisting language="php"><![CDATA[
  264. class My_Component_HelloProvider
  265. extends Zend_Tool_Framework_Provider_Abstract
  266. {
  267. public function say()
  268. {
  269. $aValue = $this->_registry->getStorage()->get("myUsername");
  270. echo "Hallo $aValue!";
  271. }
  272. }
  273. ]]>
  274. </programlisting>
  275. <para>
  276. Die API des Speichers ist sehr einfach:
  277. </para>
  278. <programlisting language="php"><![CDATA[
  279. class Zend_Tool_Framework_Client_Storage
  280. {
  281. public function setAdapter($adapter);
  282. public function isEnabled();
  283. public function put($name, $value);
  284. public function get($name, $defaultValue=null);
  285. public function has($name);
  286. public function remove($name);
  287. public function getStreamUri($name);
  288. }
  289. ]]>
  290. </programlisting>
  291. <important>
  292. <para>
  293. Wenn man eigene Provider designt die auf Konfguration oder Speicher rücksicht
  294. nehmen sollte man darauf achten ob die benötigten Benutzer-Konfigurations oder
  295. Speicher Schlüssel bereits für einen Benutzer existieren. Man würde keine
  296. fatalen Fehler erhalten wenn keine von ihnen angegeben werden, da leere
  297. Schlüssel bei der Anfrage erstellt werden.
  298. </para>
  299. </important>
  300. </sect3>
  301. </sect2>
  302. </sect1>