By now, you have probably read the earlier article on getting Zend_Tool installed and working on your development machine… (or at least you should have!) If you haven’t, you can give it a quick read to understand what Zend_Tool offers. If you want have it installed on your system without any hassle, install it via the PEAR installer (blog post about the PEAR installation and what’s offered here).
After you’ve had a chance to play with Zend_Tool in some depth though, you are bound to start asking the question “how do I extend Zend_Tool?” Which is exactly we’ll cover in the following article.
Background on Zend_Tool_Framework
In order to understand how to extend Zend_Tool, you need to know a few things about its overall structure. The whole of the system was built with extensibility in mind. Each of the major functional parts of the system are abstracted in such a way that its easy to not only extend, but to replace with completely separate implementations. For example, our initial interface to this system is a command line interface (cli), but its just as easy to replace the cli interface with an XML-RPC interface, or a web interface. Once replaced, the internals of the tooling system can remain the same, but you’ll see that you can issue requests to the system from drastically different environments.
We will strictly be dealing with the CLI client for this system in this article, but its important to know that CLI could just as easily be some other environment. To understand in greater detail how these different parts work together, you can read both the Tooling System/internals of Zend_Tool proposal, and also have a look at the CLI Specific Implementation proposal.
But for our first order of business, we’ll demonstrate how to add new commands to the Zend_Tool system.
Background on the Zend_Tool Internals
Out of the box, Zend_Tool finds all its commands on php’s include_path. Finding which files might contain what Zend_Tool calls “Providers”, is based off of some conventions set by the default Zend_Tool loader. When Zend_Tool starts up, the first thing it does is scan all the paths in your include_path in order to find files that match the regular expression “.*(?:Manifest|Provider)\.php”. That essentially says any files that end in Tool.php, Manifest.php or Provider.php. Once it finds these files, it will require_once them into the runtime, and look for any classes within them that implement either the Zend_Tool_Framework_Manifest_Interface interface or the Zend_Tool_Framework_Provider_Interface interface. If they do indeed implement this interface, these classes are loaded into the tooling system and can now be called by your client.
To illustrate how this works, open two files in a text editor, first Zend/Tool/Framework/System/Manifest.php, then Zend/Tool/Framework/System/Provider/Version.php. First thing to note is that Zend/Tool/Framework/System/Manifest.php ends in Manifest.php and the class within it (Zend_Tool_Framework_System_Manifest) implements Zend_Tool_Framework_Manifest_Interface. Classes implementing the Zend_Tool_Framework_Manifest_Interface interface allow us to tell the tooling system which “providers” can be loaded and used. This method allows us to specify multiple providers without explicitly naming them XXXXProvider.php. As you can see, in the getProviders() method, you’ll notice that it returns an array of two classes, one of those classes is Zend_Tool_Framework_System_Provider_Version.
Now, lets turn our attention to the Zend/Tool/Framework/System/Provider/Version.php file. As you can see, the class in this file implements Zend_Tool_Framework_Provider_Interface, thus it “provides” a set of capabilities that can be dispatched from the tooling system. In our last article, we saw the command “zf show version”. Effectively, that ran the show() method from the Zend_Tool_Framework_System_Provider_Version class.
Without getting into the gory details, there is are a few things we want to take away from this exercise:
- Zend/Tool/Framework/System/Manifest.php is in the php include_path, so it can be found by the Zend_Tool loader.
- Zend_Tool_Framework_System_Manifest implements Zend_Tool_Framework_Manifest_Interface which allows Zend_Tool to know what providers to load.
- Zend_Tool_Framework_System_Provider_Version is in the aforementioned Manifest file AND it implements Zend_Tool_Framework_Provider_Interface, so Zend_Tool can dispatch this “provider”
- Zend_Tool_Framework_System_Provider_Version has a show() method which can be called from the command line “zf show version”, where Version is the short name for this provider.
So, with that newly acquired knowledge, we should be able to create a hello world provider. Assuming your include_path is /usr/lib/php, lets create a file at this location: /usr/lib/php/My/HelloWorldProvider.php
Inside that file, we will put this following code:
class My_HelloWorldProvider implements Zend_Tool_Framework_Provider_Interface
public function say()
echo 'Hello World!';
Save file, and now on the command line, we should be able to issue the following command:
zf say hello-world
You SHOULD receive output that looks like this:
~$ zf say hello-world
Thats it! So lets review what just happened here:
- we created a file that ended in Provider.php (My/HelloWorldProvider.php) in our include_path.
- the class My_HelloWorldProvider implements Zend_Tool_Framework_Provider_Interface
- we saved the file, and issued the command “zf say hello-world”
At this point you might have a few questions:
How do I know what the provider name is?
The provider name is the last segment name of the class with the words “Provider” or “Manifest” stripped off the end. There are ways to override this behavior, but that is a topic for a more in-depth article.
Why is the provider name dash-separated on the command line, but camel case in the class?
The idiom you use within a specific environment (or are generally used to seeing), is kept consistent with respect to the environment you are in. So for command line, dash-separated is the common format, and in OO code, CamelCase is the common format. Zend_Tool strives to keep these namings consistent with the environment they are in.
That should get you started. As you can see, using the Zend_Tool_Framework dispatch system to script tasks and expose them through the zf command line interface is fairly easy. In upcoming articles, we’ll get into more advanced usage as well as jump into extending Zend_Tool_Project, the project management component of Zend_Tool.