Zend_Tool_Framework-WritingProviders.xml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 19568 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.tool.framework.writing-providers">
  5. <title>Creando Proveedores para usar con Zend_Tool_Framework</title>
  6. <para> In general, a provider, on its own, is nothing more than the shell
  7. for a developer to bundle up some capabilities they wish to dispatch
  8. with the command line (or other) clients. It is an analogue to what a
  9. "controller" is inside of your <acronym>MVC</acronym> application. </para>
  10. <sect2 id="zend.tool.framework.writing-providers.loading">
  11. <title>How Zend Tool finds your Providers</title>
  12. <para> By default Zend Tool uses the IncludePathLoader to find all the
  13. providers that you can run. It recursivly iterates all include path
  14. directories and opens all files that end with "Manifest.php" or
  15. "Provider.php". All classes in these files are inspected if they
  16. implement either
  17. <classname>Zend_Tool_Framework_Provider_Interface</classname> or
  18. <classname>Zend_Tool_Framework_Manifest_ProviderManifestable</classname>
  19. . Instances of the provider interface make up for the real
  20. functionality and all their public methods are accessible as
  21. provider actions. The ProviderManifestable interface however
  22. requires the implementation of a method
  23. <methodname>getProviders()</methodname> which returns an array
  24. of instantiated provider interface instances. </para>
  25. <para> The following naming rules apply on how you can access the
  26. providers that were found by the IncludePathLoader: </para>
  27. <itemizedlist>
  28. <listitem>
  29. <para> The last part of your classname split by underscore is
  30. used for the provider name, e.g. "My_Provider_Hello" leads
  31. to your provider being accessible by the name "hello".
  32. </para>
  33. </listitem>
  34. <listitem>
  35. <para> If your provider has a method
  36. <methodname>getName()</methodname> it will be used
  37. instead of the previous method to determine the name.
  38. </para>
  39. </listitem>
  40. <listitem>
  41. <para> If your provider has "Provider" as prefix, e.g. it is
  42. called <classname>My_HelloProvider</classname> it will be
  43. stripped from the name so that the provider will be called
  44. "hello". </para>
  45. </listitem>
  46. </itemizedlist>
  47. <note>
  48. <para>The IncludePathLoader does not follow symlinks, that means you
  49. cannot link provider functionality into your include paths, they
  50. have to be physically present in the include paths.</para>
  51. </note>
  52. <example id="zend.tool.framework.writing-providers.loading.example">
  53. <title>Exposing Your Providers with a Manifest</title>
  54. <para> You can expose your providers to Zend Tool by offering a
  55. manifest with a special filename ending with "Manifest.php". A
  56. Provider Manifest is an implementation of the
  57. <interface>Zend_Tool_Framework_Manifest_ProviderManifestable</interface>
  58. and requires the <methodname>getProviders()</methodname> method
  59. to return an array of instantiated providers. In anticipation of
  60. our first own provider
  61. <classname>My_Component_HelloProvider</classname> we will
  62. create the following manifest: </para>
  63. <programlisting language="php"><![CDATA[
  64. class My_Component_Manifest
  65. implements Zend_Tool_Framework_Manifest_ProviderManifestable
  66. {
  67. public function getProviders()
  68. {
  69. return array(
  70. new My_Component_HelloProvider()
  71. );
  72. }
  73. }
  74. ]]></programlisting>
  75. </example>
  76. </sect2>
  77. <sect2 id="zend.tool.framework.writing-providers.basic">
  78. <title>Basic Instructions for Creating Providers</title>
  79. <para> As an example, if a developer wants to add the capability of
  80. showing the version of a datafile that his 3rd party component is
  81. working from, there is only one class the developer would need to
  82. implement. Assuming the component is called
  83. <classname>My_Component</classname> , he would create a class
  84. named <classname>My_Component_HelloProvider</classname> in a file
  85. named <filename>HelloProvider.php</filename> somewhere on the
  86. <property>include_path</property> . This class would implement
  87. <classname>Zend_Tool_Framework_Provider_Interface</classname> ,
  88. and the body of this file would only have to look like the
  89. following: </para>
  90. <programlisting language="php"><![CDATA[
  91. class My_Component_HelloProvider
  92. implements Zend_Tool_Framework_Provider_Interface
  93. {
  94. public function say()
  95. {
  96. echo 'Hello from my provider!';
  97. }
  98. }
  99. ]]></programlisting>
  100. <para> Given that code above, and assuming the developer wishes to
  101. access this functionality through the console client, the call would
  102. look like this: </para>
  103. <programlisting language="sh"><![CDATA[
  104. % zf say hello
  105. Hello from my provider!
  106. ]]></programlisting>
  107. </sect2>
  108. <sect2 id="zend.tool.framework.writing-providers.response">
  109. <title>The response object</title>
  110. <para> As discussed in the architecture section Zend Tool allows to hook
  111. different clients for using your Zend Tool providers. To keep
  112. compliant with different clients you should use the response object
  113. to return messages from your providers instead of using
  114. <methodname>echo()</methodname> or a similiar output mechanism.
  115. Rewritting our hello provider with this knowledge it looks like: </para>
  116. <programlisting language="php"><![CDATA[
  117. class My_Component_HelloProvider
  118. extends Zend_Tool_Framework_Provider_Abstract
  119. {
  120. public function say()
  121. {
  122. $this->_registry->getResponse
  123. ->appendContent("Hello from my provider!");
  124. }
  125. }
  126. ]]></programlisting>
  127. <para> As you can see one has to extend the
  128. <classname>Zend_Tool_Framework_Provider_Abstract</classname> to
  129. gain access to the Registry which holds the
  130. <classname>Zend_Tool_Framework_Client_Response</classname>
  131. instance. </para>
  132. </sect2>
  133. <sect2 id="zend.tool.framework.writing-providers.advanced">
  134. <title>Advanced Development Information</title>
  135. <sect3 id="zend.tool.framework.writing-providers.advanced.variables">
  136. <title>Passing Variables to a Provider</title>
  137. <para> The above "Hello World" example is great for simple commands,
  138. but what about something more advanced? As your scripting and
  139. tooling needs grow, you might find that you need the ability to
  140. accept variables. Much like function signatures have parameters,
  141. your tooling requests can also accept parameters. </para>
  142. <para> Just as each tooling request can be isolated to a method
  143. within a class, the parameters of a tooling request can also be
  144. isolated in a very well known place. Parameters of the action
  145. methods of a provider can include the same parameters you want
  146. your client to utilize when calling that provider and action
  147. combination. For example, if you wanted to accept a name in the
  148. above example, you would probably do this in OO code: </para>
  149. <programlisting language="php"><![CDATA[
  150. class My_Component_HelloProvider
  151. implements Zend_Tool_Framework_Provider_Interface
  152. {
  153. public function say($name = 'Ralph')
  154. {
  155. echo 'Hello' . $name . ', from my provider!';
  156. }
  157. }
  158. ]]></programlisting>
  159. <para> The above example can then be called via the command line
  160. <command>zf say hello Joe</command> . "Joe" will be supplied
  161. to the provider as a parameter of the method call. Also note, as
  162. you see that the parameter is optional, that means it is also
  163. optional on the command line, so that <command>zf say
  164. hello</command> will still work, and default to the name
  165. "Ralph". </para>
  166. </sect3>
  167. <sect3 id="zend.tool.framework.writing-providers.advanced.prompt">
  168. <title>Prompt the User for Input</title>
  169. <para> There are cases when the workflow of your provider requires
  170. to prompt the user for input. This can be done by requesting the
  171. client to ask for more the required input by calling: </para>
  172. <programlisting language="php"><![CDATA[
  173. class My_Component_HelloProvider
  174. extends Zend_Tool_Framework_Provider_Abstract
  175. {
  176. public function say($name = 'Ralph')
  177. {
  178. $nameResponse = $this->_registry
  179. ->getClient()
  180. ->promptInteractiveInput("Whats your name?");
  181. $name = $name->getContent();
  182. echo 'Hello' . $name . ', from my provider!';
  183. }
  184. }
  185. ]]></programlisting>
  186. <para> This command throws an exception if the current client is not
  187. able to handle interactive requests. In case of the default
  188. Console Client however you will be asked to enter the name.
  189. </para>
  190. </sect3>
  191. <sect3 id="zend.tool.framework.writing-providers.advanced.pretendable">
  192. <title>Pretending to execute a Provider Action</title>
  193. <para> Another interesting feature you might wish to implement is
  194. <emphasis>pretendability</emphasis> . Pretendabilty is the
  195. ability for your provider to "pretend" as if it is doing the
  196. requested action and provider combination and give the user as
  197. much information about what it <emphasis>would</emphasis> do
  198. without actually doing it. This might be an important notion
  199. when doing heavy database or filesystem modifications that the
  200. user might not otherwise want to do. </para>
  201. <para> Pretendability is easy to implement. There are two parts to
  202. this feature: 1) marking the provider as having the ability to
  203. "pretend", and 2) checking the request to ensure the current
  204. request was indeed asked to be "pretended". This feature is
  205. demonstrated in the code sample below. </para>
  206. <programlisting language="php"><![CDATA[
  207. class My_Component_HelloProvider
  208. extends Zend_Tool_Framework_Provider_Abstract
  209. implements Zend_Tool_Framework_Provider_Pretendable
  210. {
  211. public function say($name = 'Ralph')
  212. {
  213. if ($this->_registry->getRequest()->isPretend()) {
  214. echo 'I would say hello to ' . $name . '.';
  215. } else {
  216. echo 'Hello' . $name . ', from my provider!';
  217. }
  218. }
  219. }
  220. ]]></programlisting>
  221. <para> To run the provider in pretend mode just call: </para>
  222. <programlisting language="sh"><![CDATA[
  223. % zf --pretend say hello Ralph
  224. I would say hello Ralph.
  225. ]]></programlisting>
  226. </sect3>
  227. <sect3 id="zend.tool.framework.writing-providers.advanced.verbosedebug">
  228. <title>Verbose and Debug modes</title>
  229. <para> You can also run your provider actions in "verbose" or
  230. "debug" modes. The semantics in regard to this actions have to
  231. be implemented by you in the context of your provider. You can
  232. access debug or verbose modes with: </para>
  233. <programlisting language="php"><![CDATA[
  234. class My_Component_HelloProvider
  235. implements Zend_Tool_Framework_Provider_Interface
  236. {
  237. public function say($name = 'Ralph')
  238. {
  239. if($this->_registry->getRequest()->isVerbose()) {
  240. echo "Hello::say has been called\n";
  241. }
  242. if($this->_registry->getRequest()->isDebug()) {
  243. syslog(LOG_INFO, "Hello::say has been called\n");
  244. }
  245. }
  246. }
  247. ]]></programlisting>
  248. </sect3>
  249. <sect3 id="zend.tool.framework.writing-providers.advanced.configstorage">
  250. <title>Accessing User Config and Storage</title>
  251. <para> Using the Enviroment variable
  252. <property>ZF_CONFIG_FILE</property> or the .zf.ini in your
  253. home directory you can inject configuration parameters into any
  254. Zend Tool provider. Access to this configuration is available
  255. via the registry that is passed to your provider if you extend
  256. <classname>Zend_Tool_Framework_Provider_Abstract</classname>
  257. . </para>
  258. <programlisting language="php"><![CDATA[
  259. class My_Component_HelloProvider
  260. extends Zend_Tool_Framework_Provider_Abstract
  261. {
  262. public function say()
  263. {
  264. $username = $this->_registry->getConfig()->username;
  265. if(!empty($username)) {
  266. echo "Hello $username!";
  267. } else {
  268. echo "Hello!";
  269. }
  270. }
  271. }
  272. ]]></programlisting>
  273. <para> The returned configuration is of the type
  274. <classname>Zend_Tool_Framework_Client_Config</classname> but
  275. internally the <methodname>__get()</methodname> and
  276. <methodname>__set()</methodname> magic methods proxy to a
  277. <classname>Zend_Config</classname> of the given
  278. configuration type. </para>
  279. <para> The storage allows to save arbitrary data for later
  280. reference. This can be useful for batch processing tasks or for
  281. re-runs of your tasks. You can access the storage in a similar
  282. way like the configuration: </para>
  283. <programlisting language="php"><![CDATA[
  284. class My_Component_HelloProvider
  285. extends Zend_Tool_Framework_Provider_Abstract
  286. {
  287. public function say()
  288. {
  289. $aValue = $this->_registry->getStorage()->get("myUsername");
  290. echo "Hello $aValue!";
  291. }
  292. }
  293. ]]></programlisting>
  294. <para> The API of the storage is very simple: </para>
  295. <programlisting language="php"><![CDATA[
  296. class Zend_Tool_Framework_Client_Storage
  297. {
  298. public function setAdapter($adapter);
  299. public function isEnabled();
  300. public function put($name, $value);
  301. public function get($name, $defaultValue=null);
  302. public function has($name);
  303. public function remove($name);
  304. public function getStreamUri($name);
  305. }
  306. ]]></programlisting>
  307. <important>
  308. <para> When designing your providers that are config or storage
  309. aware remember to check if the required user-config or
  310. storage keys really exist for a user. You won't run into
  311. fatal errors when none of these are provided though, since
  312. empty ones are created upon request. </para>
  313. </important>
  314. </sect3>
  315. </sect2>
  316. </sect1>