View Source


<p>Tutorial Part 3: The Zend_Tool Manifest</p>

<p><strong>Understanding what the Manifest is for</strong></p>

<p>By now, you are at least familiar with executing actions within Zend_Tool and also have a simple understanding of how to create your own provider. In part 3 of our Zend_Tool tutorial series, we will cover the Zend_Tool_Framework_Manifest, which is a place where metadata about clients, actions, providers and other &quot;tooling&quot; components resides.</p>

<p>Simply put, the Manifest will contain structured information (metadata) about components within Zend_Tool. Once this metadata is inside the Zend_Tool Manifest, it can be used by anyone who wishes to query for it and utilize it. To further understand its power, lets have a look at it from the perspective of an already implemented use case.</p>

<p>Inside Zend_Tool_Framework_Client_Cli (our cli interface into Zend Tool), we have a manifest <ac:link><ri:page ri:content-title="located at Zend_Tool_Framework_Client_Cli_Manifest" /></ac:link>. At startup time for Zend Tool, this manifest is loaded and creates metadata that is specific to the CLI client. This information is available to any client, action, and/or provider that wants to utilize this information by nature of the Zend_Tool manifest system. So what exactly is this metadata? What problem does it solve?</p>

<p>Well, lets back up and look at our provider we created in part two:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

class My_HelloWorldTool implements Zend_Tool_Framework_Provider_Interface
{}

]]></ac:plain-text-body></ac:macro>

<p>Notice the name of this class: My_HelloWorldTool. We know that the loader will strip of the prefix of the class as well as the &quot;Tool&quot; part of the class name. This leaves us with &quot;HelloWorld&quot; - a name that is formatted as a CamelCase separated set of words. While this is good for working within the php environment (in the PHP environment we are used to and expect seeing classes, variables, array keys, and so on in CamelCase). But unfortunately, CamelCase is not the dominant means of word separation for the command line interface. More often than not, we see words in the command line environment are separated by dash-separators. Not only are they dash separated, but they are generally lower cased. So, our &quot;HelloWorld&quot; provider, while it makes sense in the PHP Environment, makes more sense as &quot;hello-world&quot; in the command line environment.</p>

<p>This is where our manifest and metadata comes in. When Zend_Tool is setting up, the Zend_Tool_Framework_Client_Cli_Manifest waits until all the providers have been loaded then starts doing a name translation of all PHP Environment specific names of providers, actions and parameters that it can find. For the actual translation, Zend_Tool_Framework_Client_Cli_Manifest will use the Zend_Filter_Word_* filters to translate from &quot;CamelCase&quot; to &quot;dashed-lower-separated&quot;. For each word it finds, it creates a metadata object, and puts that object into the registry for later retrieval.</p>

<p><strong>Retrieving metadata</strong></p>

<p>Since information already exists inside the manifest, we can start digging into usage by querying existing data in the manifest. As we have seen above, the CLI client for Zend_Tool already puts information into the manifest we can start looking for, so lets start with some examples on how to get that information out. At this point, we will continue on with our My_HelloWorld provider example, as it will give us hooks into an already running and setup Zend_Tool environment.</p>

<p>Currently, our My_HelloWorldProvider class should look something like this:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

class My_HelloWorldProvider implements Zend_Tool_Framework_Provider_Interface
{

public function say()
{
echo 'Hello World!';
}

}

]]></ac:plain-text-body></ac:macro>

<p>We will create a show() method will will use as our playground for exploring how to query the manifest. More on this later.</p>

<p>The first thing to note is the the Manifest is essentially a registry of Metadata objects. That said, to get an instance of the Manifest, its as similar as getting an instance from the application registry:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

$manifest = Zend_Tool_Framework_Manifest_Registry::getInstance();

]]></ac:plain-text-body></ac:macro>

<p>Now that you have an instance of the manifest, it makes sense to talk about its api and what you can do with this manifest object. At this point, we'll discuss this in the code example below.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

class Zend_Tool_Framework_Manifest_Registry
{
// this method is what we will use for getting an instance of the manifest registry
// of metadata objects
public static function getInstance();

// this method is of less importance to querying the manifest and is
// more for adding a manifest to be processed at Zend_Tool setup time,
// more on this later.
public function addManifest(Zend_Tool_Framework_Manifest_Interface $manifest)

// also, another method that is of little importance in querying, but will be mentioned
// later on.
public function process()

// this method is a a query method that will return an array of metadata that matches
// the search properties supplied in the first parameter, aptly named searchProperties
// the $includeNonExistentProperties is important when you have a ridgid set of
// search parameters, and still want to return a peice of metadata that all of the
// search properties that it does support.
public function getMetadatas(Array $searchProperties = array(), $includeNonExistentProperties = true)

// same as above, but will return a single metadata object (the first matching one
// it finds)
public function getMetadata(Array $searchProperties = array(), $includeNonExistentProperties = true)

}

]]></ac:plain-text-body></ac:macro>

<p>So, getMetadatas() and getMetadata() are the two methods one would need to get familiar with using in order to get the needed information out of the registry. So, before jumping into our query example, lets understand what a metadata object will look like. The basic metadata object (Zend_Tool_Framework_Manifest_Metadata) is quite simple:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
<?php

class Zend_Tool_Framework_Manifest_Metadata
{
protected $_type = 'Global';
protected $_name = null;
protected $_value = null;
protected $_reference = null;

public function __construct(Array $options = array())
public function setOptions(Array $options)
public function getType()
public function setType($type)
public function getName()
public function setName($name)
public function getValue()
public function setValue($value)
public function setReference($reference)
public function getReference()
}
]]></ac:plain-text-body></ac:macro>

<p>It contains the ability to track its type, a name and a value for itself, and some object to reference. When querying, if a searchProperties is set as array('name'=&gt;'MyName','value'=&gt;'myValue'), then this object will be checked via getName() and getValue() respectively to see if this metadata matches the queried for properties.</p>

<p>While this is the most basic metadata, there are two other built in metadata objects that extends this metadata object that will be of interest to developers: Zend_Tool_Framework_Manifest_ActionMetadata and Zend_Tool_Framework_Manifest_ProviderMetadata.</p>

<p>These classes (respectively) look like this:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

class Zend_Tool_Framework_Manifest_ActionMetadata extends Zend_Tool_Framework_Manifest_Metadata
{
protected $_type = 'Action';
protected $_actionName = null;
public function setActionName($actionName)
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 setProviderName($providerName)
public function getProviderName()
public function setActionName($actionName)
public function getActionName()
public function setSpecialtyName($specialtyName)
public function getSpecialtyName()
}

]]></ac:plain-text-body></ac:macro>

<p>Again, these objects can be queried by any of the get*() methods that are exposed by their class apis, so array('providerName'=&gt;'HelloWorld') is a completely acceptable set of search properties.</p>

<p>Now that that is covered, time to get to the nitty gritty code. Inside our show() method of our My_HelloWorldProvider, lets specify a query that will find the metadata about the My_HelloWorldProvider</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

public function show()
{

$manifest = Zend_Tool_Framework_Manifest_Registry::getInstance();
$metadatas = $manifest->getMetadatas(array('providerName' => 'HelloWorld'));
Zend_Debug::dump($metadatas);

Zend_Tool_Framework_Client_Registry::getInstance()->response->appendContent($output); count($metadatas) . ' metadata objects were found.';

}

]]></ac:plain-text-body></ac:macro>

<p>Now, we can run the command &lt;pre&gt;zf show hello-world&lt;/pre&gt; and it will dump out an array of metadata objects that match the set of search parameters above. At this point, take a moment to tweak the search parameters. For example, to be more specific you could supply array('providerName' =&gt; 'HelloWorld', 'name' =&gt; 'cliProviderName') to get a more specific set of results.</p>

<p><strong>Adding information to the Manifest Registry</strong></p>

<p>Now that you understand what's currently in the registry and how to query it, it makes it easier to understand how to build the information to put into the registry.</p>

<p>Here, there first thing to note is that the Zend_Tool loader will look for any *Manifest.php files on the include path. If they are found, they are then checked to make sure they implement the Zend_Tool_Framework_Manifest_Interface interface. This interface simply enforces that a getMetadata() method exists. These Manifest classes are then put in an internal queue to be processed when all providers are done loading. This is done so that each and every manifest will have a chance to create metadata dynamically (if need be) for all providers and actions that are loaded into the system.</p>

<p>As an example, lets add some generic metadata to the manifest about our HelloWorld provider. In order to do this, well have to create a Manifest class as well as a method that will return our metadata.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[

class My_HelloWorldManifest implements Zend_Tool_Framework_Manifest_Interface
{

public function getMetadata()
{
$metadata = new Zend_Tool_Framework_Manifest_ProviderMetadata();
$metadata->setOptions(array(
'providerName' => 'HelloWorld',
'name' => 'fooName',
'value' => 'barValue',
'reference' => Zend_Tool_Provider_Registry::getInstance()->getProvider('HelloWorld')
));
}

}

]]></ac:plain-text-body></ac:macro>

<p>Now, if you re-run that last 'zf show hello-world', you will see there is a new metadata object is returned, with name 'fooName', and value 'barValue', also there will be a reference to the 'HelloWorld' provider object.</p>

<p>Ultimately, the Manifest is for information that needs to be persisted in the Zend_Tool environment regardless of which client is doing the dispatching and regardless of which action or provider is being dispatched.</p>