<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.tool.framework.architecture">
    <title>Architecture</title>

    <sect2 id="zend.tool.framework.architecture.registry">
        <title>Registry</title>

        <para>
            Because providers and manifests may come from anywhere in the
            <code>include_path</code>, a registry is provided to simplify access
            to the various pieces of the toolchain. This registry is injected
            into registry-aware components, which may then pull dependencies
            from them as necessary. Most dependencies registered with the
            registry will be sub-component-specific repositories.
        </para>

        <para>
            The interface for the registry consists of the following definition:
        </para>

        <programlisting role="php"><![CDATA[
interface Zend_Tool_Framework_Registry_Interface
{
    public function setClient(Zend_Tool_Framework_Client_Abstract $client);
    public function getClient();
    public function setLoader(Zend_Tool_Framework_Loader_Abstract $loader);
    public function getLoader();
    public function setActionRepository(
        Zend_Tool_Framework_Action_Repository $actionRepository
    );
    public function getActionRepository();
    public function setProviderRepository(
        Zend_Tool_Framework_Provider_Repository $providerRepository
    );
    public function getProviderRepository();
    public function setManifestRepository(
        Zend_Tool_Framework_Manifest_Repository $manifestRepository
    );
    public function getManifestRepository();
    public function setRequest(Zend_Tool_Framework_Client_Request $request);
    public function getRequest();
    public function setResponse(Zend_Tool_Framework_Client_Response $response);
    public function getResponse();
}
]]></programlisting>

        <para>
            The various objects the registry manages will be discussed in their
            appropriate sections.
        </para>

        <para>
            Classes that should be registry-aware should implement
            <classname>Zend_Tool_Framework_Registry_EnabledInterface</classname>. This
            interface merely allows initialization of the registry in the target
            class.
        </para>

        <programlisting role="php"><![CDATA[
interface Zend_Tool_Framework_Registry_EnabledInterface
{
    public function setRegistry(
        Zend_Tool_Framework_Registry_Interface $registry
    );
}
]]></programlisting>
    </sect2>

    <sect2 id="zend.tool.framework.architecture.providers">
        <title>Providers</title>

        <para>
            <classname>Zend_Tool_Framework_Provider</classname> represents the functional
            or "capability" aspect of the framework.  Fundamentally,
            <classname>Zend_Tool_Framework_Provider</classname> will provide the
            interfaces necessary to produce "providers", or bits of tooling
            functionality that can be called and used inside the
            <classname>Zend_Tool_Framework</classname> toolchain. The simplistic nature of
            implementing this provider interface allows the developer a
            "one-stop-shop" of adding functionality/capabilities to
            <classname>Zend_Tool_Framework</classname>.
        </para>

        <para>
            The provider interface is an empty interface and enforces no methods
            (this is the Marker Interface pattern):
        </para>

        <programlisting role="php"><![CDATA[
interface Zend_Tool_Framework_Provider_Interface
{}
]]></programlisting>

        <para>
            Or, if you wish, you can implement the base (or abstract) Provider
            which will give you access to the
            <classname>Zend_Tool_Framework_Registry</classname>:
        </para>

        <programlisting role="php"><![CDATA[
abstract class Zend_Tool_Framework_Provider_Abstract
    implements Zend_Tool_Framework_Provider_Interface,
               Zend_Tool_Registry_EnabledInterface
{
    protected $_registry;
    public function setRegistry(
        Zend_Tool_Framework_Registry_Interface $registry
    );
}
]]></programlisting>

    </sect2>

    <sect2 id="zend.tool.framework.architecture.loaders">
        <title>Loaders</title>

        <para>
            The purpose of a Loader is to find Providers and Manifest files that
            contain classes which implement either
            <code>Zend_Tool_Framework_Provider_Interface</code> or
            <code>Zend_Tool_Framework_Manifest_Interface</code>. Once these files are found
            by a loader, providers are loaded into the Provider Repository and
            manifest metadata is loaded into the Manifest Repository.
        </para>


        <para>
            To implement a loader, one must extend the following abstract class:
        </para>

        <programlisting role="php"><![CDATA[
abstract class Zend_Tool_Framework_Loader_Abstract
{

    abstract protected function _getFiles();

    public function load()
    {
        /** ... */
    }
}
]]></programlisting>

        <para>
            The <code>_getFiles()</code> method should return an array of files (absolute
            paths).  The built-in loader supplied with ZF is called the
            IncludePath loader. By default, the Tooling framework will use an
            include_path based loader to find files that might include Providers
            or Manifest Metadata objects.
            <code>Zend_Tool_Framework_Loader_IncludePathLoader</code>, without
            any other options, will search for files inside the include path
            that end in <code>Mainfest.php</code>, <code>Tool.php</code> or
            <code>Provider.php</code>. Once found, they will be tested (by the
            <code>load()</code> method of the
            <code>Zend_Tool_Framework_Loader_Abstract</code>) to determine if
            they implement any of the supported interfaces. If they do, an
            instance of the found class is instantiated, and it is appended to
            the proper repository.
        </para>

        <programlisting role="php"><![CDATA[
class Zend_Tool_Framework_Loader_IncludePathLoader
    extends Zend_Tool_Framework_Loader_Abstract
{

    protected $_filterDenyDirectoryPattern = '.*(/|\\\\).svn';
    protected $_filterAcceptFilePattern = '.*(?:Manifest|Provider)\.php$';

    protected function _getFiles()
    {
        /** ... */
    }
}
]]></programlisting>

        <para>
            As you can see, the IncludePath loader will search all include_paths
            for the files that match the <code>$_filterAcceptFilePattern</code>
            and NOT match the <code>$_filterDenyDirectoryPattern</code>.
        </para>
    </sect2>

    <sect2 id="zend.tool.framework.architecture.manifests">
        <title>Manifests</title>

        <para>
            In short, the Manifest shall contain specific or arbitrary metadata
            that is useful to any provider or client, as well as be responsible
            for loading any additional providers into the provider repository.
        </para>

        <para>
            To introduce metadata into the manifest repository, all one must do
            is implement the empty <code>Zend_Tool_Framework_Manifest_Interface</code>, and
            provide a <code>getMetadata()</code> method which shall return an array of
            objects that implement <code>Zend_Tool_Framework_Manifest_Metadata</code>.
        </para>

        <programlisting role="php"><![CDATA[
interface Zend_Tool_Framework_Manifest_Interface
{
    public function getMetadata();
}
]]></programlisting>

        <para>
            Metadata objects are loaded (by a loader defined below) into the
            Manfiest Repository (<code>Zend_Tool_Framework_Manifest_Repository</code>).
            Manifests will be processed after all Providers have been found a
            loaded into the provider repository. This shall allow Manifests to
            created Metadata objects based on what is currently inside the
            provider repository.
        </para>

        <para>
            There are a few different metadata classes that can be used to
            describe metadata.  The
            <code>Zend_Tool_Framework_Manifest_Metadata</code> is the base
            metadata object.  As you can see by the following code
            snippet, the base metadata class is fairly lightweight and
            abstract in nature:
        </para>

        <programlisting role="php"><![CDATA[
class Zend_Tool_Framework_Metadata_Basic
{

    protected $_type        = 'Global';
    protected $_name        = null;
    protected $_value       = null;
    protected $_reference   = null;

    public function getType();
    public function getName();
    public function getValue();
    public function getReference();
    /** ... */
}
]]></programlisting>

        <para>
            There are other built in metadata classes as well for describing
            more specialized metadata: <code>ActionMetadata</code> and
            <code>ProviderMetadata</code>.  These classes will help you describe
            in more detail metadata that is specific to either actions or
            providers, and the reference is expected to be a reference to an
            action or a provider respectively.  These classes are described in
            the follow code snippet.
        </para>

        <programlisting role="php"><![CDATA[
class Zend_Tool_Framework_Manifest_ActionMetadata
    extends Zend_Tool_Framework_Manifest_Metadata
{

    protected $_type = 'Action';
    protected $_actionName = null;

    public function getActionName();
    /** ... */
}

class Zend_Tool_Framework_Manifest_ProviderMetadata
    extends Zend_Tool_Framework_Manifest_Metadata
{

    protected $_type = 'Provider';
    protected $_providerName  = null;
    protected $_actionName    = null;
    protected $_specialtyName = null;

    public function getProviderName();
    public function getActionName();
    public function getSpecialtyName();
    /** ... */
}
]]></programlisting>

        <para>
            'Type' in these classes is used to describe the type of metadata the
            object is responsible for.  In the cases of the
            <code>ActionMetadat</code>a, the type would be 'Action', and
            conversely in the case of the <code>ProviderMetadata</code> the type
            is 'Provider'.  These metadata types will also include additional
            structured information about both the "thing" they are describing as
            well as the object (the <code>->getReference()</code>) they are
            referencing with this new metadata.
        </para>

        <para>
            In order to create your own metadata type, all one must do is extend
            the base <code>Zend_Tool_Framework_Manifest_Metadata</code> class
            and return these new metadata objects via a local Manifest
            class/object.  These user based classes will live in the Manifest
            Repository
        </para>

        <para>
            Once these metadata objects are in the repository there are then two
            different methods that can be used in order to search for them in
            the repository.
        </para>

        <programlisting role="php"><![CDATA[
class Zend_Tool_Framework_Manifest_Repository
{
    /**
     * To use this method to search, $searchProperties should contain the names
     * and values of the key/value pairs you would like to match within the
     * manifest.
     *
     * For Example:
     *     $manifestRepository->findMetadatas(array(
     *         'action' => 'Foo',
     *         'name'   => 'cliActionName'
     *         ));
     *
     * Will find any metadata objects that have a key with name 'action' value
     * of 'Foo', AND a key named 'name' value of 'cliActionName'
     *
     * Note: to either exclude or include name/value pairs that exist in the
     * search critera but do not appear in the object, pass a bool value to
     * $includeNonExistentProperties
     */
    public function findMetadatas(Array $searchProperties = array(),
                                  $includeNonExistentProperties = true);

    /**
     * The following will return exactly one of the matching search criteria,
     * regardless of how many have been returned.  First one in the manifest is
     * what will be returned.
     */
    public function findMetadata(Array $searchProperties = array(),
                                 $includeNonExistentProperties = true)
    {
        $metadatas = $this->getMetadatas($searchProperties,
                                         $includeNonExistentProperties);
        return array_shift($metadatas);
    }
}
]]></programlisting>

        <para>
            Looking at the search methods above, the signatures allow for
            extremely flexible searching.  In order to find a metadata object,
            simply pass in an array of matching constraints via an array.  If
            the data is accessible through the Property accessor (the
            <code>getSomething()</code> methods implemented on the metadata
            object), then it will be passed back to the user as a "found"
            metadata object.
        </para>
    </sect2>

    <sect2 id="zend.tool.framework.architecture.clients">
        <title>Clients</title>

        <para>
            Clients are the interface which bridges a user or external tool into
            the <code>Zend_Tool_Framework</code> system. Clients can come in all
            shapes and sizes: RPC endpoints, Command Line Interface, or
            even a web interface.  Zend_Tool has implemented the command
            line interface as the default interface for interacting with
            the <code>Zend_Tool_Framework</code> system.
        </para>

        <para>
            To implement a client, one would need to extend the following
            abstract class:
        </para>

        <programlisting role="php"><![CDATA[
abstract class Zend_Tool_Framework_Client_Abstract
{
    /**
     * This method should be implemented by the client implementation to
     * construct and set custom loaders, request and response objects.
     *
     * (not required, but suggested)
     */
    protected function _preInit();

    /**
     * This method should be implemented by the client implementation to parse
     * out and setup the request objects action, provider and parameter
     * information.
     */
    abstract protected function _preDispatch();

    /**
     * This method should be implemented by the client implementation to take
     * the output of the response object and return it (in an client specific
     * way) back to the Tooling Client.
     *
     * (not required, but suggested)
     */
    abstract protected function _postDispatch();
}
]]></programlisting>

        <para>
            As you can see, there 1 method required to fulfill the needs of a
            client (two others suggested), the initialization, prehandling and post handling.  For a
            more in depth study of how the command line client works, please see
            the <ulink url="http://framework.zend.com/svn/framework/standard/branches/release-1.8/library/Zend/Tool/Framework/Client/Console.php">source code</ulink>.
        </para>

    </sect2>
</sect1>
