1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- EN-Revision: 19568 -->
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
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>
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".
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.
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
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>
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()
78 new My_Component_HelloProvider()
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
102 <programlisting language="php"><![CDATA[
103 class My_Component_HelloProvider
104 implements Zend_Tool_Framework_Provider_Interface
106 public function say()
108 echo 'Hello from my provider!';
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[
119 Hello from my provider!
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()
139 $this->_registry->getResponse
140 ->appendContent("Hello from my provider!");
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>
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')
178 echo 'Hello' . $name . ', from my provider!';
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
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')
206 $nameResponse = $this->_registry
208 ->promptInteractiveInput("Whats your name?");
209 $name = $name->getContent();
211 echo 'Hello' . $name . ', from my provider!';
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.
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')
247 if ($this->_registry->getRequest()->isPretend()) {
248 echo 'I would say hello to ' . $name . '.';
250 echo 'Hello' . $name . ', from my provider!';
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.
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')
279 if($this->_registry->getRequest()->isVerbose()) {
280 echo "Hello::say has been called\n";
282 if($this->_registry->getRequest()->isDebug()) {
283 syslog(LOG_INFO, "Hello::say has been called\n");
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>
301 <programlisting language="php"><![CDATA[
302 class My_Component_HelloProvider
303 extends Zend_Tool_Framework_Provider_Abstract
305 public function say()
307 $username = $this->_registry->getConfig()->username;
308 if(!empty($username)) {
309 echo "Hello $username!";
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()
335 $aValue = $this->_registry->getStorage()->get("myUsername");
336 echo "Hello $aValue!";
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);
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>