Tuesday, September 17, 2013

Using ZFTool.phar for Basic Project Management

Introduction

Welcome to another tutorial. Today, I will be giving you a walk through of zftool, which provides basic tooling support in Zend Framework 2. If you’re new to Zend Framework, or have been reading the introductory series here, it can come in quite handy.
But unlike other frameworks, such as Yii (through yiic) and Symfony (via the Command Line tool), the tooling support in Zend Framework 2 is rather light on.
These respective tools provide rather robust support for automatically generating models from database connections, checking logs and a host of other much required functionality.
I understand from some tweets with Enrico Zimuel new additions are planned for zftool. But for right now, Zend Framework is definitely the junior. However, that aside, I like to take the adage of a glass half full and see zftool as a good start. Today we’re going to use it to carry out the following tasks:
  1. Create a basic ZF2 project
  2. Create several modules
  3. Creating an autoloader classmap
  4. Checking if there are any issues
By the end of today’s tutorial, you will have a good understanding of how to get started with it and to be able to use it in your projects. Firstly, let’s install zftool and get started.
Note for Windows Users This tutorial is run under Ubuntu Linux. However, with only minor changes, you can run it in your version of Windows as well.

Installation

There are a number of ways in which zftool can be installed, including using Composer and downloading the Phar tool.
During the research for this article, I tried to install it via Composer, but continuously met with permission related errors. As a result, I’ve chosen to focus on the Phar tool approach, which works, almost, seamlessly.
If you’d like to go down the Composer route, run the following command in your Terminal or console and you’ll have it available.

$ composer require zendframework/zftool:dev-master
 
Otherwise, download the phar file. Once it’s downloaded, run the following commands. These make it accessible universally on your system:


sudo cp -v zftool.phar /usr/local/bin/
cd /usr/local/bin/
sudo ln -s zftool.phar zftool
sudo chmod +x zftool.phar 
 
If you’re not familiar with the Linux command line, what we’ve done here is to copy zftool.phar to one of the directories automatically in a users PATH.
Then we’ve created a symlink to it, giving it a simpler name and finally set the executable bit on it – now it’s ready to run.

Running the Phar Tool

Now that we have the Phar file available, let’s have a look at the options available. Running the following command will display a help screen, showing all of the options supported:
zftool -v
ZFTool - Zend Framework 2 command line Tool

--------------------------------------------------------------------------------------------------------------------------------------------------------
ZFTool
--------------------------------------------------------------------------------------------------------------------------------------------------------

Basic information:
  zftool modules [list]         show loaded modules                                                                            
  zftool version | --version    display current Zend Framework version                                                         

Diagnostics
  zftool diag [options] [module name]    run diagnostics                                                                       

  [module name]    (Optional) name of module to test                                                                                                 
  -v --verbose     Display detailed information.                                                                                                     
  -b --break       Stop testing on first failure                                                                                                     
  -q --quiet       Do not display any output unless an error occurs.                                                                                 
  --debug          Display raw debug info from tests.                                                                                                

Application configuration:
  zftool config list                  list all configuration options                                                           
  zftool config get <name>            display a single config value, i.e. "config get db.host"                                 
  zftool config set <name> <value>    set a single config value (use only to change scalar values)                             

Project creation:
  zftool create project <path>    create a skeleton application                                                                

  <path>    The path of the project to be created                                                                                                    

Module creation:
  zftool create module <name> [<path>]    create a module                                                                      

  <name>    The name of the module to be created                                                                                                     
  <path>    The root path of a ZF2 application where to create the module                                                                            

Controller creation:
  zftool create controller <name> <module> [<path>]    create a controller in module                                           

  <name>      The name of the controller to be created                                                                                               
  <module>    The module in which the controller should be created                                                                                   
  <path>      The root path of a ZF2 application where to create the controller                                                                      

Action creation:
  zftool create action <name> <controllerName> <module> [<path>]    create an action in a controller                           

  <name>              The name of the action to be created                                                                                           
  <controllerName>    The name of the controller in which the action should be created                                                               
  <module>            The module containing the controller                                                                                           
  <path>              The root path of a ZF2 application where to create the action                                                                  

Classmap generator:
  zftool classmap generate <directory> <classmap file> [--append|-a] [--overwrite|-w]                                          

  <directory>         The directory to scan for PHP classes (use "." to use current directory)                                                       
  <classmap file>     File name for generated class map file  or - for standard output. If not supplied, defaults to autoload_classmap.php inside    
                      <directory>.                                                                                                                   
  --append | -a       Append to classmap file if it exists                                                                                           
  --overwrite | -w    Whether or not to overwrite existing classmap file                                                                             

Zend Framework 2 installation:
  zftool install zf <path> [<version>]                                                                                         

  <path>       The directory where to install the ZF2 library                                                                                        
  <version>    The version to install, if not specified uses the last available                                                                      

Reason for failure: Invalid arguments or no arguments provided


Creating a Project

Ok, with the tool ready to go, let’s set about using some of it’s functionality to creating and managing a Zend Framework 2 project, as outlined above.

Create the Project

Firstly, we’ll create a raw project, called ‘simple project’. To do so, run the following command:

$ php zftool.phar create project ./simpleproject

This will create the core project files in a directory in the current directory, called ‘simpleproject’. It will give you output similar to that below:
 
ZF2 skeleton application installed in ./simpleproject.
In order to execute the skeleton application you need to install the ZF2 library.
Execute: "composer.phar install" in ./simpleproject
For more info in ./simpleproject/README.md 
 
Assuming there were no permission issues, the project directory should look as follows:

$ ls -l ./simpleproject/
-rw-rw-r-- 1 maltblue maltblue    342 Jun 12 06:34 composer.json
-rwxr-xr-x 1 maltblue maltblue 709565 Jun 12 06:34 composer.phar
drwxrwxr-x 3 maltblue maltblue   4096 Jun 12 06:34 config
drwxrwxr-x 3 maltblue maltblue   4096 Jun 12 06:34 data
-rw-rw-r-- 1 maltblue maltblue   1807 Jun 12 06:34 init_autoloader.php
-rw-rw-r-- 1 maltblue maltblue   1548 Jun 12 06:34 LICENSE.txt
drwxrwxr-x 3 maltblue maltblue   4096 Jun 12 06:34 module
drwxrwxr-x 5 maltblue maltblue   4096 Jun 12 06:34 public
-rw-rw-r-- 1 maltblue maltblue   1759 Jun 12 06:34 README.md
drwxrwxr-x 3 maltblue maltblue   4096 Jun 12 06:34 vendor

The Generated composer.json File

Looking in the project directory, we see a new composer.json file, which has the basic configuration and requirements for a Zend Framework 2 project. If you’d like to go further, feel free to alter it as suits your needs, running composer update afterwards.
 
 
{
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "require": {
        "php": ">=5.5.3",
        "zendframework/zendframework": ">2.2.0rc1",
        "zendframework/zend-developer-tools": "dev-master",
        "zendframework/zftool": "dev-master",
    
    }
}

Installing Zend Framework 2 in the Project (With Composer)

With the basic files in place, unless you have the Zend Framework libraries on your path, the application won’t run. So, in the project directory, run composer.phar install to bring in the required libraries and dependencies.
The output will look similar to that below. I’ve trimmed it for sakes of readability.
 
$ composer.phar install  (or) $ php composer.phar install
 
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing zendframework/zendframework (2.2.0)
    Downloading: 100%             

Writing lock file
Generating autoload files

Creating a Module

Now let’s create a module which doesn’t already exist; we’ll call it Generic. As before, we create the module via the command below:

zftool.phar create module Generic

You should see output similar to that below, indicating there were no problems.
 
The module Generic has been created

Looking in the Generic module directory, we see the following structure:
 
$ ls -l module/Generic/
total 16
drwxrwxr-x 2 maltblue maltblue 4096 Jun 12 06:47 config
-rw-rw-r-- 1 maltblue maltblue  437 Jun 12 06:47 Module.php
drwxrwxr-x 3 maltblue maltblue 4096 Jun 12 06:47 src
drwxrwxr-x 2 maltblue maltblue 4096 Jun 12 06:47 view


Under config is a module.config.php file. So, we now have the basic structure of a ZF2 module.

Viewing a List of Modules

But what if we want to see the list of modules? Well, here’s where I hit an issue. I believe the following command will show us that list.

$ php zftool.phar modules (or) $zftool modules

But no matter what I tried, it always resulted in the following error:
No modules installed. Are you in the root folder of a ZF2 application?
At this stage, I’m not sure if it’s a bug or a user (me) problem. However, as I get more information, I’ll update the post about this issue.

Classmap Generation

Ok, we’re just about done. If you’re familiar with Zend Framework 2, you’ll know that performance can be increased through a classmap file.
A class map file stores a map of files which the application may require, saving it from performing a file location resolution. Effectively, it’s a class file location cache.
Let’s assume we have a series of classes in the module directory. Let’s create a classmap file for it. To do so, we run the following command:

$ zftool classmap generate module/ autoload_classmap.php
 
This looks for all class files in the module directory and then writes it out to autoadclassmap.php in the current directory. It will have output similar to that below:
 
Creating classmap file for library in /home/parallels/zftool/vendor/simpleproject/module
Scanning for files containing PHP classes .... DONE
Found 4 PHP classes
Creating classmap code ... DONE

Writing classmap to autoload_classmap.php...  DONE
Wrote classmap to /home/parallels/zftool/vendor/simpleproject/autoload_classmap.php

The Generated Classmap File

If you’ve not seen a classmap file before, here’s what the one we just created looks like (formatted for better readability):
    $ cat autoload_classmap.php 
    <?php
    // Generated by Zend Framework 2
    return array(
        'Generic\Module' => DIR . '/module/Generic/Module.php',
        'Application\Controller\IndexController' => DIR . 
'/module/Application/src/Application/Controller/IndexController.php',
        'Application\Module' => DIR . '/module/Application/Module.php',
        'Users\Module' => DIR . '/module/Users/Module.php',

Running Diagnostics

Now on to the last command we’re going to run, module diagnostics. I’m going to run diagnostics on the new, Generic, module we’ve created in this tutorial. From the project root, run the following command:
 
$ zftool diag --debug Generic

This will run diagnostics, showing debug information. In this case, just re-iterating the running version of PHP.


itadmin@itadmin-AcerPower-Series:/var/www/simpleproject$ zftool diag --debug Generic
Starting diagnostics:
  OK   ZF: PHP Version: Current PHP version is 5.5.3-1+debphp.org~precise+2
       -------------------------------------------------------------------------------------------------------------------------------------------------
       '5.5.3-1+debphp.org~precise+2'
       -------------------------------------------------------------------------------------------------------------------------------------------------

OK (1 diagnostic tests)                                                                                                                                

itadmin@itadmin-AcerPower-Series:/var/www/simpleproject$                                                                                                      

Verbose Information

Running it again, with the verbose flag set, show’s approximately the same information, just less detailed. We can see here there were no issues with the module. So there was nothing to report.
 
itadmin@itadmin-AcerPower-Series:/var/www/simpleproject$ zftool diag --debug Application
Starting diagnostics:
  OK   ZF: PHP Version: Current PHP version is 5.5.3-1+debphp.org~precise+2
       -------------------------------------------------------------------------------------------------------------------------------------------------
       '5.5.3-1+debphp.org~precise+2'
       -------------------------------------------------------------------------------------------------------------------------------------------------

OK (1 diagnostic tests)                                                                                                                                

itadmin@itadmin-AcerPower-Series:/var/www/simpleproject$                                                                                                      

I must admit I’m not quite sure of the intent of the diagnostic tool. I’ve renamed Module.php in Generic, renamed the Generic module directory, yet still the tool reports everything is ok.
I’ll be doing so more research into this and updating the article with what is found.

Sunday, August 25, 2013

Zend Framework 2 event manager

Understanding the Zend Framework 2 event manager

The event manager is without any doubt one of the least known Zend Framework 2 component. Nevertheless, it is a very powerful component which offers a lot of flexibility when used correctly. This short article aims to help you to use it.

Why using the event manager?

The event manager allows event driven programming. It allows to flexibly connect different parts of the code to each other, without having a wrong, inverted dependency.
The event manager is extensively used internally (that’s why we said that ZF 2 is an event-driven framework). Thus, contrary to Zend Framework 1, most of MVC elements (routing, dispatching, view…) are not called one after another. Instead, framework triggers events (“dispatch”, “route”…). Other objects listen those events and, in turn, do something in response of those events. We can extract some wording:
  • Objects trigger events. Those events are named (“route”, “dispatch”, “sendTweet”…) and often contain additional parameters (for instance, an event called “sendTweet” could contain the tweet’s content).
  • Other objects listen (they are called listeners) those events to do something. In other ways, we attach objects to events.

The TweetService example

The nice thing about the event manager is that not only the framework can use them! Let’s take a simple example: we have written a TweetService class whose goal is to send a tweet thanks to the Twitter API.
namespace Tweet\Service;

class TweetService
{
    /**
     * @param string $content
     */
    public function sendTweet($content)
    {
        // Send a tweet through Twitter API...
    }
}
But this crazy marketing guy said us that it could be fun to send an email to the tweet’s author too:
namespace Tweet\Service;

class TweetService
{
    /**
     * @param string $content
     */
    public function sendTweet($content)
    {
        // Send a tweet through Twitter's API...

        // Send a mail
        $mailService->send(...);
    }
}
But it’s not enough for him, he also wants SMS:
namespace Tweet\Service;

class TweetService
{
    /**
     * @param string $content
     */
    public function sendTweet($content)
    {
        // Send a tweet through Twitter's API...

        // Send an e-mail...
        $mailService->send(...);

        // Send a SMS...
        $smsService->send(...);
    }
}
Some problems quickly arise:
  • Our TwitterService now depends on the application. This specific application requires that a mail and SMS are sent, but maybe another one will just send the tweet, while another one will add a message to a queue. This is exactly what we want to avoid when we create a “generic” module whose aim is to be a “drop-in” module.
  • Furthermore, the TweetService depends on two other services too: an email service and SMS service. This means: every time we want to use the TwitterService module, we also must download the EmailService and SMSService modules, even if we don’t use them.

How to use it

Trigger an event

A very elegant solution to this problem is directly bundled into Zend Framework 2 : the event manager. Thus, we are going to simply trigger an event to say “hey mate, a tweet has been sent” instead of hard-coding what to do. Our code is then modified this way:
namespace Tweet\Service;

use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;

class TweetService implements EventManagerAwareInterface
{
    /**
     * @var EventManagerInterface
     */
    protected $eventManager;

    /**
     * @param string $content
     */
    public function sendTweet($content)
    {
        // Send the tweet with Twitter's API...

        // Trigger an event
        $this->getEventManager()->trigger('sendTweet', null, array('content' => $content));
    }

    /**
     * @param  EventManagerInterface $eventManager
     * @return void
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $this->eventManager = $eventManager;
    }

    /**
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        return $this->eventManager;
    }
}
As we can see, we now only trigger an event called “sendTweet”. It’s up to the mail and/or SMS service to listen to this event to send an email/SMS.
You can also notice that this class implements the EventManagerAwareInterface interface. When we create an object that implements this interface through the service manager, Zend Framework 2 will automatically inject a new event manager for us by calling the setEventManager method.

Add listeners

Most of the time, listeners are added in the Module.php file, more precisely in the onBootstrap method. This is the easiest and recommended way. Intuitively, this is what most people do when they are first introduced to the event manager:
namespace Tweet;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $eventManager = $event->getApplication()->getEventManager();
        $eventManager->attach('sendTweet', function($e) {
            var_dump($e);
        }, 100);
    }
}
This code is pretty simple: we retrieve the application’s event manager, and add a callback (through a closure) that is called when the event sendTweet is triggered.
Unfortunately… this does not work. I know I know, you may think this is not intuitive, but there are reasons for that. Let’s introduce the shared event manager !

The shared event manager

Let’s go back to the TweetService. Earlier, I said that when a class implements the EventManagerAwareInterface, ZF 2 automatically inject a new event manager. I need to emphasize on the word new!
As a consequence, when we trigger the event sendTweet in the TweetService class, because the event manager is different (once again, it is a new event manager), the TweetService’s event manager has absolutely no knowledge about listeners that could have been added to other event managers. And this is absolutely what we were doing in the previous code snippet, as we were attaching a listener to the application’s event manager (which is different from the TwitterService’s one).
You may ask yourself why ZF 2 does not inject the same event manager everywhere. This way, the problem would be solved. But if you think about it more, this could rise even more problems. For instance, let’s imagine an event called send. Multiple objects may trigger an event called send, but for completely different purposes (send could be an event’s name used to send an email, a SMS, a HTTP request or whatever!). This would mean that listeners could receive event for things they would not be interested at all.
That’s why each object has its own event manager, with its own events.
To solve our previous example, we need to use a so-called shared event manager. A shared event manager is a manage which is unique across the application, and that is injected into each event manager (yeah I know, it’s not easy to grasp !). Let’s modify our Module.php code in order to attach the event into the shared event manager instead:
namespace Tweet;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $eventManager       = $event->getApplication()->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();

        $sharedEventManager->attach('Tweet\Service\TweetService', 'sendTweet', function($e) {
            var_dump($e);
        }, 100);
    }
}
First, we retrieve the shared event manager from the application’s event manager. Then, we attach a listener. The subtlety is the first parameter whose value is here Tweet\Service\TweetService. Indeed, currently, without this parameter, the event manager of our TweetService has no way to “get” the listeners of the event it triggers.
Thus, we need to slightly modify our setEventManager method in TweetService:
public function setEventManager(EventManagerInterface $eventManager)
{
    $eventManager->addIdentifiers(array(
        get_called_class()
    ));

    $this->eventManager = $eventManager;
}
Now, everything is linked properly. We are adding here a new identifier whose value is get_called_class() (in this case, it is equals to Tweet\Service\TweetService). When this service will trigger the event sendTweet, here is what will happen internally:
  1. The TweetService’s event manager will check if objects are listening to sendTweet, which is not the case here because the listeners have been added to the shared event manager (remember the Module.php code!).
  2. The event manager will then retrieve the shared event manager (remember it is unique !). Then, for each of its identifiers (in our case, it only has one, which is get_called_class), it will check if an event was added to the event sendTweet with the given identifier. In other words, it will check if there is a registered listener for the event sendTweet with the identifier Tweet\Service\TweetService (=== get_called_class()). This is exactly what we did in the onBootstrap method!
  3. Finally, for each listener, the callback will be executed (in our example, we simply called a var_dump($e)).
This identifier mechanism is really powerful. For instance, let’s imagine we want to trigger the event sendTweet in several services. We could add another, more generic, identifier:
public function setEventManager(EventManagerInterface $eventManager)
{
    $eventManager->addIdentifiers(array(
        'Application\Service\ServiceInterface',
        get_called_class()
    ));

    $this->eventManager = $eventManager;
}
Now, update the Module.php class:
namespace Tweet;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $eventManager       = $event->getApplication()->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();

        // This listener will be called ONLY if the sendTweet event is triggered
        // by an event manager that has the Tweet\Service\TweetService identifier !
        $sharedEventManager->attach('Tweet\Service\TweetService', 'sendTweet', function($e) {
            var_dump($e);
        }, 100);

        // This listener will be called for all events sendTweet from all event
        // manager that has the identifier Application\Service\ServiceInterface,
        // so potentially a lot
        $sharedEventManager->attach('Application\Service\ServiceInterface', 'sendTweet', function($e) {
            var_dump($e);
        }, 100);
    }
}

The special case of MVC events

I said earlier that we should use the shared event manager. But there is one specific case: the event manager we retrieve from the onBootstrap method is the MVC event manager. This means that this event manager knows the events triggered by the framework. This means that if you want to add listeners to the events of the Zend\Mvc\MvcEvent class, you can do it without using the shared event manager:
namespace Tweet;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $eventManager = $event->getApplication()->getEventManager();
        $eventManager->attach(MvcEvent::EVENT_ROUTE, function($e) {
            var_dump($e);
        }, 100);
    }
}

Let’s clean that…

In the previous example, we used a closure to define what the listeners must do. This is quick and easy, but if you have a lot of listeners, this can quickly be a mess. Furthermore, if you want to attach the same listener to multiple events, it will irremediably lead to a code duplication.
Hopefully, we can do it better by creating new classes that implement Zend\EventManager\ListenerAggregateInterface interface (starting from ZF 2.2, you can instead extend the abstract class Zend\EventManager\AbstractListenerAggregate). This interface asks you to write two methods: attach and detach. Here is the class that adds a listener to the sendTweet event:
namespace Tweet\Listener;

use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;

class SendListener implements ListenerAggregateInterface
{
    /**
     * @var \Zend\Stdlib\CallbackHandler[]
     */
    protected $listeners = array();

    /**
     * {@inheritDoc}
     */
    public function attach(EventManagerInterface $events)
    {
        $sharedEvents      = $events->getSharedManager();
        $this->listeners[] = $sharedEvents->attach('Tweet\Service\TweetService', 'sendTweet', array($this, 'onSendTweet'), 100);
    }

    public function detach(EventManagerInterface $events)
    {
        foreach ($this->listeners as $index => $listener) {
            if ($events->detach($listener)) {
                unset($this->listeners[$index]);
            }
        }
    }

    public function onSendTweet($e)
    {
        var_dump($e);
    }
}
This way, the onBootstrap method is simplified, and allow to move logic to specific classes instead of polluting the Module.php class:
public function onBootstrap(EventInterface $e)
{
    $eventManager = $e->getTarget()->getEventManager();
    $eventManager->attach(new SendListener());
}