| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 19568 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.tool.framework.writing-providers">
- <title>Creando Proveedores para usar con Zend_Tool_Framework</title>
- <para> In general, a provider, on its own, is nothing more than the shell
- for a developer to bundle up some capabilities they wish to dispatch
- with the command line (or other) clients. It is an analogue to what a
- "controller" is inside of your <acronym>MVC</acronym> application. </para>
- <sect2 id="zend.tool.framework.writing-providers.loading">
- <title>How Zend Tool finds your Providers</title>
- <para> By default Zend Tool uses the IncludePathLoader to find all the
- providers that you can run. It recursivly iterates all include path
- directories and opens all files that end with "Manifest.php" or
- "Provider.php". All classes in these files are inspected if they
- implement either
- <classname>Zend_Tool_Framework_Provider_Interface</classname> or
- <classname>Zend_Tool_Framework_Manifest_ProviderManifestable</classname>
- . Instances of the provider interface make up for the real
- functionality and all their public methods are accessible as
- provider actions. The ProviderManifestable interface however
- requires the implementation of a method
- <methodname>getProviders()</methodname> which returns an array
- of instantiated provider interface instances. </para>
- <para> The following naming rules apply on how you can access the
- providers that were found by the IncludePathLoader: </para>
- <itemizedlist>
- <listitem>
- <para> The last part of your classname split by underscore is
- used for the provider name, e.g. "My_Provider_Hello" leads
- to your provider being accessible by the name "hello".
- </para>
- </listitem>
- <listitem>
- <para> If your provider has a method
- <methodname>getName()</methodname> it will be used
- instead of the previous method to determine the name.
- </para>
- </listitem>
- <listitem>
- <para> If your provider has "Provider" as prefix, e.g. it is
- called <classname>My_HelloProvider</classname> it will be
- stripped from the name so that the provider will be called
- "hello". </para>
- </listitem>
- </itemizedlist>
- <note>
- <para>The IncludePathLoader does not follow symlinks, that means you
- cannot link provider functionality into your include paths, they
- have to be physically present in the include paths.</para>
- </note>
- <example id="zend.tool.framework.writing-providers.loading.example">
- <title>Exposing Your Providers with a Manifest</title>
- <para> You can expose your providers to Zend Tool by offering a
- manifest with a special filename ending with "Manifest.php". A
- Provider Manifest is an implementation of the
- <interface>Zend_Tool_Framework_Manifest_ProviderManifestable</interface>
- and requires the <methodname>getProviders()</methodname> method
- to return an array of instantiated providers. In anticipation of
- our first own provider
- <classname>My_Component_HelloProvider</classname> we will
- create the following manifest: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_Manifest
- implements Zend_Tool_Framework_Manifest_ProviderManifestable
- {
- public function getProviders()
- {
- return array(
- new My_Component_HelloProvider()
- );
- }
- }
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.basic">
- <title>Basic Instructions for Creating Providers</title>
- <para> As an example, if a developer wants to add the capability of
- showing the version of a datafile that his 3rd party component is
- working from, there is only one class the developer would need to
- implement. Assuming the component is called
- <classname>My_Component</classname> , he would create a class
- named <classname>My_Component_HelloProvider</classname> in a file
- named <filename>HelloProvider.php</filename> somewhere on the
- <property>include_path</property> . This class would implement
- <classname>Zend_Tool_Framework_Provider_Interface</classname> ,
- and the body of this file would only have to look like the
- following: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say()
- {
- echo 'Hello from my provider!';
- }
- }
- ]]></programlisting>
- <para> Given that code above, and assuming the developer wishes to
- access this functionality through the console client, the call would
- look like this: </para>
- <programlisting language="sh"><![CDATA[
- % zf say hello
- Hello from my provider!
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.response">
- <title>The response object</title>
- <para> As discussed in the architecture section Zend Tool allows to hook
- different clients for using your Zend Tool providers. To keep
- compliant with different clients you should use the response object
- to return messages from your providers instead of using
- <methodname>echo()</methodname> or a similiar output mechanism.
- Rewritting our hello provider with this knowledge it looks like: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $this->_registry->getResponse
- ->appendContent("Hello from my provider!");
- }
- }
- ]]></programlisting>
- <para> As you can see one has to extend the
- <classname>Zend_Tool_Framework_Provider_Abstract</classname> to
- gain access to the Registry which holds the
- <classname>Zend_Tool_Framework_Client_Response</classname>
- instance. </para>
- </sect2>
- <sect2 id="zend.tool.framework.writing-providers.advanced">
- <title>Advanced Development Information</title>
- <sect3 id="zend.tool.framework.writing-providers.advanced.variables">
- <title>Passing Variables to a Provider</title>
- <para> The above "Hello World" example is great for simple commands,
- but what about something more advanced? As your scripting and
- tooling needs grow, you might find that you need the ability to
- accept variables. Much like function signatures have parameters,
- your tooling requests can also accept parameters. </para>
- <para> Just as each tooling request can be isolated to a method
- within a class, the parameters of a tooling request can also be
- isolated in a very well known place. Parameters of the action
- methods of a provider can include the same parameters you want
- your client to utilize when calling that provider and action
- combination. For example, if you wanted to accept a name in the
- above example, you would probably do this in OO code: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say($name = 'Ralph')
- {
- echo 'Hello' . $name . ', from my provider!';
- }
- }
- ]]></programlisting>
- <para> The above example can then be called via the command line
- <command>zf say hello Joe</command> . "Joe" will be supplied
- to the provider as a parameter of the method call. Also note, as
- you see that the parameter is optional, that means it is also
- optional on the command line, so that <command>zf say
- hello</command> will still work, and default to the name
- "Ralph". </para>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.prompt">
- <title>Prompt the User for Input</title>
- <para> There are cases when the workflow of your provider requires
- to prompt the user for input. This can be done by requesting the
- client to ask for more the required input by calling: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say($name = 'Ralph')
- {
- $nameResponse = $this->_registry
- ->getClient()
- ->promptInteractiveInput("Whats your name?");
- $name = $name->getContent();
- echo 'Hello' . $name . ', from my provider!';
- }
- }
- ]]></programlisting>
- <para> This command throws an exception if the current client is not
- able to handle interactive requests. In case of the default
- Console Client however you will be asked to enter the name.
- </para>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.pretendable">
- <title>Pretending to execute a Provider Action</title>
- <para> Another interesting feature you might wish to implement is
- <emphasis>pretendability</emphasis> . Pretendabilty is the
- ability for your provider to "pretend" as if it is doing the
- requested action and provider combination and give the user as
- much information about what it <emphasis>would</emphasis> do
- without actually doing it. This might be an important notion
- when doing heavy database or filesystem modifications that the
- user might not otherwise want to do. </para>
- <para> Pretendability is easy to implement. There are two parts to
- this feature: 1) marking the provider as having the ability to
- "pretend", and 2) checking the request to ensure the current
- request was indeed asked to be "pretended". This feature is
- demonstrated in the code sample below. </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- implements Zend_Tool_Framework_Provider_Pretendable
- {
- public function say($name = 'Ralph')
- {
- if ($this->_registry->getRequest()->isPretend()) {
- echo 'I would say hello to ' . $name . '.';
- } else {
- echo 'Hello' . $name . ', from my provider!';
- }
- }
- }
- ]]></programlisting>
- <para> To run the provider in pretend mode just call: </para>
- <programlisting language="sh"><![CDATA[
- % zf --pretend say hello Ralph
- I would say hello Ralph.
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.verbosedebug">
- <title>Verbose and Debug modes</title>
- <para> You can also run your provider actions in "verbose" or
- "debug" modes. The semantics in regard to this actions have to
- be implemented by you in the context of your provider. You can
- access debug or verbose modes with: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- implements Zend_Tool_Framework_Provider_Interface
- {
- public function say($name = 'Ralph')
- {
- if($this->_registry->getRequest()->isVerbose()) {
- echo "Hello::say has been called\n";
- }
- if($this->_registry->getRequest()->isDebug()) {
- syslog(LOG_INFO, "Hello::say has been called\n");
- }
- }
- }
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.tool.framework.writing-providers.advanced.configstorage">
- <title>Accessing User Config and Storage</title>
- <para> Using the Enviroment variable
- <property>ZF_CONFIG_FILE</property> or the .zf.ini in your
- home directory you can inject configuration parameters into any
- Zend Tool provider. Access to this configuration is available
- via the registry that is passed to your provider if you extend
- <classname>Zend_Tool_Framework_Provider_Abstract</classname>
- . </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $username = $this->_registry->getConfig()->username;
- if(!empty($username)) {
- echo "Hello $username!";
- } else {
- echo "Hello!";
- }
- }
- }
- ]]></programlisting>
- <para> The returned configuration is of the type
- <classname>Zend_Tool_Framework_Client_Config</classname> but
- internally the <methodname>__get()</methodname> and
- <methodname>__set()</methodname> magic methods proxy to a
- <classname>Zend_Config</classname> of the given
- configuration type. </para>
- <para> The storage allows to save arbitrary data for later
- reference. This can be useful for batch processing tasks or for
- re-runs of your tasks. You can access the storage in a similar
- way like the configuration: </para>
- <programlisting language="php"><![CDATA[
- class My_Component_HelloProvider
- extends Zend_Tool_Framework_Provider_Abstract
- {
- public function say()
- {
- $aValue = $this->_registry->getStorage()->get("myUsername");
- echo "Hello $aValue!";
- }
- }
- ]]></programlisting>
- <para> The API of the storage is very simple: </para>
- <programlisting language="php"><![CDATA[
- class Zend_Tool_Framework_Client_Storage
- {
- public function setAdapter($adapter);
- public function isEnabled();
- public function put($name, $value);
- public function get($name, $defaultValue=null);
- public function has($name);
- public function remove($name);
- public function getStreamUri($name);
- }
- ]]></programlisting>
- <important>
- <para> When designing your providers that are config or storage
- aware remember to check if the required user-config or
- storage keys really exist for a user. You won't run into
- fatal errors when none of these are provided though, since
- empty ones are created upon request. </para>
- </important>
- </sect3>
- </sect2>
- </sect1>
|