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