Robert Basic's blog

Posts tagged 'zf'

Using Doctrine DBAL with Zend Expressive

by Robert Basic on December 22, 2016.

The Doctrine project comes with a database abstraction and access layer — Doctrine DBAL — which I prefer over other abstraction layers like Zend DB.

My good friend James, aka Asgrim, has written already how to integrate Zend Expressive and Doctrine ORM.

But what if want to use only the DBAL with Zend Expressive, and not the entire ORM?

It’s pretty easy as all we need to do is write one short factory that will create the database connection using the connection parameters we provide to it:

src/App/Infrastructure/Database/ConnectionFactory.php

<?php declare(strict_types=1);

namespace App\Infrastructure\Database;

use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Driver\Connection;
use Interop\Container\ContainerInterface;

class ConnectionFactory
{
    public function __invoke(ContainerInterface $container) : Connection
    {
        $config = $container->get('config');
        $connectionParams = $config['db'];

        return DriverManager::getConnection($connectionParams);
    }
}

Configuration of the database connection is pretty straightforward as well:

config/database.php

<?php declare(strict_types=1);

return [
    'db' => [
        'driver' => 'pdo_pgsql',
        'dbname' => 'database_name',
        'user' => 'username',
        'password' => 'password',
        'host' => 'localhost',
        'port' => 5432,
    ]
];

For other options and possible values, take a look at the configuration documentation.

Next, we configure a container-interop service locator, like Zend ServiceManager to be able to access the database connection in parts of the application where we need it. This configuration consists of mapping a factory name to the ConnectionFactory factory:

config/dependencies.php

<?php declare(strict_types=1);

return [
    'dependencies' => [
        'factories' => [
            'db' => App\Infrastructure\Database\ConnectionFactory::class,
            // other factories ...
        ],
        // other type of dependencies ...
    ]
];

Now all we need to access the database connection is to grab it from the ContainerInterface container somewhere in our application and we’re all set:

src/App/SomeObjectFactory.php

<?php declare(strict_types=1);

namespace App;

use Interop\Container\ContainerInterface;

class SomeObjectFactory
{
    public function __invoke(ContainerInterface $container) : SomeObject
    {
        $connection = $container->get('db');
        return new SomeObject($connection);
    }
}

We can now use this $connection object to further create the query builder, work with transactions, the schema manager and other features the Doctrine DBAL provides us. Nice and easy.

Happy hackin’!

Tags: dbal, doctrine, zend expressive, zf.
Categories: Development, Programming, Software.

Need help on your PHP projects? Let's talk!

Events in a Zend Expressive application

by Robert Basic on August 04, 2016.

Three weeks ago I wrote a post on how to utilize Tactician in a Zend Expressive application. Today I want to expand on that post a little by adding the possibility to trigger and listen to events using the Zend EventManager component.

Using events allows our application to respond to different events that occur during a request. For example, when a user registers a new account, our application can trigger an event, UserRegistered, that can let the rest of our application know when a new registration happens. With the help of the EventManager we attach listeners to that event. When the UserRegistered event is triggered, the event manager will invoke all the listeners that are listening to that particular event.

This allows for a better separation of concerns in some cases, because if we take this approach, our code that deals with registering new users doesn’t care any more what happens after that — do we send out a welcoming email to the user, a notification to the site admins, create a log entry somewhere… It just registers a new account, triggers the event and that’s it.

Let’s see some code

As I mentioned earlier, this post expands on my previous post, so all we are going to add is an event that gets triggered when the Ping command is handled, an event listener that listens to that event and wire it all together with the event manager.

Let’s include the Zend EventManager in our project with composer:

$ composer require zendframework/zend-eventmanager

Next we expand the factory for the Ping command handler. We create an EventManager object that we will pass to the Ping command handler, so that we can trigger events:

src/App/CommandHandler/PingFactory.php

diff --git a/src/App/CommandHandler/PingFactory.php b/src/App/CommandHandler/PingFactory.php
index e995d1a..0737631 100644
--- a/src/App/CommandHandler/PingFactory.php
+++ b/src/App/CommandHandler/PingFactory.php
@@ -3,6 +3,7 @@
 namespace App\CommandHandler;
 
 use Interop\Container\ContainerInterface;
+use Zend\EventManager\EventManager;
 
 class PingFactory
 {
@@ -10,6 +11,11 @@ class PingFactory
     {
         $logPath = '/tmp/ping-command.log';
 
-        return new Ping($logPath);
+        $events = new EventManager();
+        $events->setIdentifiers([
+            Ping::class
+        ]);
+
+        return new Ping($logPath, $events);
     }
}

Later on we will use the same event manager to attach event listeners to our events.

In the Ping command handler we use the event manager, that we pass in as a constructor argument from the ping command handler factory, to trigger events:

src/App/CommandHandler/Ping.php

diff --git a/src/App/CommandHandler/Ping.php b/src/App/CommandHandler/Ping.php
index 538e3af..9768738 100644
--- a/src/App/CommandHandler/Ping.php
+++ b/src/App/CommandHandler/Ping.php
@@ -2,15 +2,19 @@
 
 namespace App\CommandHandler;
 
+use Zend\EventManager\EventManagerInterface;
 use App\Command\Ping as PingCommand;
 
 class Ping
 {
     private $logPath;
 
-    public function __construct($logPath)
+    private $events;
+
+    public function __construct($logPath, EventManagerInterface $events)
     {
         $this->logPath = $logPath;
+        $this->events = $events;
     }
 
     public function __invoke(PingCommand $pingCommand)
@@ -18,5 +22,12 @@ class Ping
         $commandTime = $pingCommand->getCommandTime();
 
         file_put_contents($this->logPath, $commandTime . PHP_EOL, FILE_APPEND);
+
+        $params = [
+            'command_time' => $commandTime,
+            'event_time' => time(),
+        ];
+
+        $this->events->trigger('ping_command_handled', $this, $params);
     }
}

The main part is the call to the trigger method on the event manager. The first argument, ping_command_handled, is the event’s name. We will use that event name to attach to it later. The second argument is the target of the event and usually it’s the object instance that triggers the event. Finally with the third argument we can send out optional parameters with the event which we can access in our event listeners.

Even though we have no listeners attached to the event, our application will continue to work perfectly fine, because an event is not required to have any listeners. It doesn’t make much sense to have events without listeners, but it wouldn’t break our application.

Shhh… Listen!

The simplest way to attach a listener to the event would be to tell the event manager to call a callable every time the event is triggered. This would also mean we need to set up any and all dependencies our event listeners have, at the moment of attaching the listener to the event, even though the event can end up not being triggered at all. All that dependency set up can be costly and wasteful.

Zend EventManager comes with lazy listeners that allows to fetch event listeners from a container-interop compatible container. This lets us to set up the dependency graph for an event listener in a factory, which will be invoked by the lazy listener only when the event we are listening to is triggered. If the event is triggered, the lazy listener will fetch the event listener from the container along with it’s dependencies, but if the event is not triggered, nothing will happen. Super useful!

Let’s attach our event listener to the event using the lazy listener:

src/App/CommandHandler/PingFactory.php

diff --git a/src/App/CommandHandler/PingFactory.php b/src/App/CommandHandler/PingFactory.php
index 0737631..5ce9c7e 100644
--- a/src/App/CommandHandler/PingFactory.php
+++ b/src/App/CommandHandler/PingFactory.php
@@ -4,6 +4,7 @@ namespace App\CommandHandler;
 
 use Interop\Container\ContainerInterface;
 use Zend\EventManager\EventManager;
+use Zend\EventManager\LazyListener;
+use App\EventListener\Ping as PingEventListener;
 
 class PingFactory
 {
@@ -16,6 +17,13 @@ class PingFactory
             Ping::class
         ]);
 
+        $lazyListener = new LazyListener([
+            'listener' => PingEventListener::class,
+            'method' => 'onPingCommandHandled',
+        ], $container);
+
+        $events->attach('ping_command_handled', $lazyListener);
+
         return new Ping($logPath, $events);
     }
}

We create a new LazyListener object and as the first argument to it we pass an array with the actual event listener and method that will be called when the event is triggered. The second argument is the container-interop compatible container, which knows how to build our event listener.

After that we attach the lazy listener to the events we are interested in, in this case the event called ping_command_handled. Once that event gets triggered, the lazy listener will get our PingEventListener from the container and call the onPingCommandHandled method on it.

Let’s quickly tell the container how to create our event listener:

config/autoload/dependencies.global.php

diff --git a/config/autoload/dependencies.global.php b/config/autoload/dependencies.global.php
index 794304e..cf47c99 100644
--- a/config/autoload/dependencies.global.php
+++ b/config/autoload/dependencies.global.php
@@ -21,6 +21,7 @@ return [
             Helper\UrlHelper::class => Helper\UrlHelperFactory::class,
             'CommandBus' => App\CommandBusFactory::class,
             App\CommandHandler\Ping::class => App\CommandHandler\PingFactory::class,
+            App\EventListener\Ping::class => App\EventListener\Ping::class,
         ],
     ],
];

And finally our event listener looks something like this:

src/App/EventListener/Ping.php

<?php
namespace App\EventListener;
use Interop\Container\ContainerInterface;
use Zend\EventManager\Event;
class Ping
{
    public function __invoke(ContainerInterface $container)
    {
        // Grab some dependencies from the $container
        // And return self
        return new self();
    }

    public function onPingCommandHandled(Event $event)
    {
        // Do something with the $event here
        $name = $event->getName();
        $target = $event->getTarget();
        $params = $event->getParams();
    }
}

When the container grabs our event listener the __invoke method will be invoked at which point we can grab the event listener’s dependencies from the container. Once the event listener object is created, the onPingCommandHandled method will be called by the event manager when the event is triggered.

Happy hackin’!

Tags: container, event listener, event manager, events, php, zend expressive, zf.
Categories: Development, Programming.

Need help on your PHP projects? Let's talk!

Using Tactician in a Zend Expressive application

by Robert Basic on July 13, 2016.

I spent some time connecting the dots last week, so I decided to put together an example on how to get started with using Tactician in a Zend Expressive application. The example itself is not really useful, but it does show how to setup the dependencies and get started with these two libraries.

Zend Expressive is a PSR7 compatible microframework that provides interfaces for routing, DI containers, templating and error handling. It provides a couple out of the box, so you can either use those, or write your own implementations.

Tactician is a command bus library whose goal is to make using the command pattern easy to use in your applications. It allows to have an object that represents a command, pass it on to the command bus which will figure out which command handler should take care of that command.

Let’s dive in

To get up and running quickly with Zend Expressive we can create a skeleton application. It does some basic wiring for us, like setting up the routing and the DI container.

It also comes with a dummy ping action, at /api/ping, which just gives us the current unix timestamp. This example is going to expand on that and create a Ping command that will be handled by a Ping command handler. The command handler will get some additional dependencies from the container, just to make the example a bit more interesting.

Creating the skeleton application is really easy with Composer:

$ cd /var/www
$ composer create-project zendframework/zend-expressive-skeleton tactician-example

Bring in the Tactician and the tactician-container plugin as project dependencies. The tactician-container plugin allows us to lazy load command handlers from a container-interop compatible container:

$ composer require league/tactician
$ composer require league/tactician-container

Now that we have all our libraries in, let’s change how the container creates the Ping action. Before it was being just invoked by the container, but now we want to create it through a factory:

config/autoload/routes.global.php

diff --git a/config/autoload/routes.global.php b/config/autoload/routes.global.php
index 856f5ab..8335450 100644
--- a/config/autoload/routes.global.php
+++ b/config/autoload/routes.global.php
@@ -4,10 +4,10 @@ return [
     'dependencies' => [
         'invokables' => [
             Zend\Expressive\Router\RouterInterface::class => Zend\Expressive\Router\FastRouteRouter::class,
-            App\Action\PingAction::class => App\Action\PingAction::class,
         ],
         'factories' => [
             App\Action\HomePageAction::class => App\Action\HomePageFactory::class,
+            App\Action\PingAction::class => App\Action\PingFactory::class
         ],
     ],

This will allow us to pass in dependencies to the PingAction class.

The Ping action’s factory is simple:

src/App/Action/PingFactory.php

<?php

namespace App\Action;

use Interop\Container\ContainerInterface;

class PingFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $commandBus = $container->get('CommandBus');

        return new PingAction($commandBus);
    }
}

We are telling the container to get the service called CommandBus and pass it as an argument to the Ping action’s constructor.

Wiring in Tactician

We haven’t yet defined the CommandBus service, so let’s do that next by telling the service manager to create the CommandBus using the App\CommandBusFactory factory:

config/autoload/dependencies.global.php

diff --git a/config/autoload/dependencies.global.php b/config/autoload/dependencies.global.php
index b2b08f5..460c045 100644
--- a/config/autoload/dependencies.global.php
+++ b/config/autoload/dependencies.global.php
@@ -19,6 +19,7 @@ return [
         'factories' => [
             Application::class => ApplicationFactory::class,
             Helper\UrlHelper::class => Helper\UrlHelperFactory::class,
+            'CommandBus' => App\CommandBusFactory::class
         ],
     ],
 ];

This factory sets up the Tactician’s command bus and is the main point of this example:

src/App/CommandBusFactory.php

<?php

namespace App;

use League\Tactician\CommandBus;
use League\Tactician\Handler\CommandHandlerMiddleware;
use League\Tactician\Container\ContainerLocator;
use League\Tactician\Handler\CommandNameExtractor\ClassNameExtractor;
use League\Tactician\Handler\MethodNameInflector\InvokeInflector;
use Interop\Container\ContainerInterface;

class CommandBusFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $inflector = new InvokeInflector();

        $commandsMapping = [];
        $locator = new ContainerLocator($container, $commandsMapping);

        $nameExtractor = new ClassNameExtractor();

        $commandHandlerMiddleware = new CommandHandlerMiddleware(
            $nameExtractor,
            $locator,
            $inflector
        );

        $commandBus = new CommandBus([
            $commandHandlerMiddleware
        ]);

        return $commandBus;
    }
}

Tactician uses a command handler middleware to handle commands. That middleware in turn uses a name extractor to get the command name out of a command, a locator to find the actual command handler and an inflector to figure out the method to call on the command handler to handle the command. Tactician’s middleware system is nicely described in the documentation.

The ClassNameExtractor will extract the command name from the class name.

The ContainerLocator will use our container-interop compatible container to find the command handler, which in this example is Zend ServiceManager.

The InvokeInflector dictates that the command handler needs to have an __invoke method which will get our Ping command as an argument and then it’s up to the Ping command handler to handle the command.

The $commandsMapping array that we are passing to the locator is going to be a map of commands and their handlers. We’ll populate that later on.

In the next step, let’s tell the PingAction’s constructor to accept the command bus:

src/App/Action/PingAction.php

diff --git a/src/App/Action/PingAction.php b/src/App/Action/PingAction.php
index ea2ae22..612fb32 100644
--- a/src/App/Action/PingAction.php
+++ b/src/App/Action/PingAction.php
@@ -5,9 +5,15 @@ namespace App\Action;
 use Zend\Diactoros\Response\JsonResponse;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use League\Tactician\CommandBus;

 class PingAction
 {
+    public function __construct(CommandBus $commandBus)
+    {
+        $this->commandBus = $commandBus;
+    }
+
     public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
     {
         return new JsonResponse(['ack' => time()]);

Cool, at this point we have everything set up to start sending and handling commands.

Commands and their handlers

The command we are going to create is a simple one:

src/App/Command/Ping.php

<?php

namespace App\Command;

class Ping
{
    private $commandTime;

    public function __construct()
    {
        $this->commandTime = time();
    }

    public function getCommandTime()
    {
        return $this->commandTime;
    }
}

It just sets the command time to the current unix timestamp.

Updating the PingAction to include the creation of our Ping command and passing it on to the command bus to be handled:

src/App/Action/PingAction.php

diff --git a/src/App/Action/PingAction.php b/src/App/Action/PingAction.php
index 612fb32..6cb9334 100644
--- a/src/App/Action/PingAction.php
+++ b/src/App/Action/PingAction.php
@@ -6,6 +6,7 @@ use Zend\Diactoros\Response\JsonResponse;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use League\Tactician\CommandBus;
+use App\Command\Ping as PingCommand;

 class PingAction
 {
@@ -16,6 +17,11 @@ class PingAction

     public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
     {
-        return new JsonResponse(['ack' => time()]);
+        $pingCommand = new PingCommand();
+        $time = $pingCommand->getCommandTime();
+
+        $this->commandBus->handle($pingCommand);
+
+        return new JsonResponse(['ack' => $time]);
     }
 }

Now is the time to let Tactician know about our command and command handler mapping, so it knows which handler handles which command:

src/App/CommandBusFactory.php

diff --git a/src/App/CommandBusFactory.php b/src/App/CommandBusFactory.php
index ba587f6..b79fbb1 100644
--- a/src/App/CommandBusFactory.php
+++ b/src/App/CommandBusFactory.php
@@ -9,13 +9,18 @@ use League\Tactician\Handler\CommandNameExtractor\ClassNameExtractor;
 use League\Tactician\Handler\MethodNameInflector\InvokeInflector;
 use Interop\Container\ContainerInterface;

+use App\Command\Ping as PingCommand;
+use App\CommandHandler\Ping as PingCommandHandler;
+
 class CommandBusFactory
 {
     public function __invoke(ContainerInterface $container)
     {
         $inflector = new InvokeInflector();

-        $commandsMapping = [];
+        $commandsMapping = [
+            PingCommand::class => PingCommandHandler::class
+        ];
         $locator = new ContainerLocator($container, $commandsMapping);

         $nameExtractor = new ClassNameExtractor();

We’re almost there. I promise.

The command handler is going to be created through a factory, so we can inject dependencies into it:

src/App/CommandHandler/PingFactory.php

<?php

namespace App\CommandHandler;

use Interop\Container\ContainerInterface;

class PingFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $logPath = '/tmp/ping-command.log';

        return new Ping($logPath);
    }
}

It doesn’t do much, it just passes a path to a log file. Of course, in real code, you’d probably pass in some dependency gotten from the container.

The command handler won’t do much either, it’s just going to log the the ping’s command time in the log file we passed in from the command handler factory:

src/App/CommandHandler/Ping.php

<?php

namespace App\CommandHandler;

use App\Command\Ping as PingCommand;

class Ping
{
    private $logPath;

    public function __construct($logPath)
    {
        $this->logPath = $logPath;
    }

    public function __invoke(PingCommand $pingCommand)
    {
        $commandTime = $pingCommand->getCommandTime();

        file_put_contents($this->logPath, $commandTime . PHP_EOL, FILE_APPEND);
    }
}

And finally let the service manager know how to create the Ping command handler:

config/autoload/dependencies.global.php

diff --git a/config/autoload/dependencies.global.php b/config/autoload/dependencies.global.php
index 460c045..2c8e3ee 100644
--- a/config/autoload/dependencies.global.php
+++ b/config/autoload/dependencies.global.php
@@ -19,7 +19,8 @@ return [
         'factories' => [
             Application::class => ApplicationFactory::class,
             Helper\UrlHelper::class => Helper\UrlHelperFactory::class,
-            'CommandBus' => App\CommandBusFactory::class
+            'CommandBus' => App\CommandBusFactory::class,
+            App\CommandHandler\Ping::class => App\CommandHandler\PingFactory::class
         ],
     ],
 ];

Navigating to /api/ping should display the {“ack”:1468171544} response, and the log file at /tmp/ping-command.log should have the same timestamp logged.

That was a lot of code

I know, looks like an awful lot of code just to log a timestamp in a file somewhere. But the point is that even for more complicated commands and handlers the basic wiring stays the same — create the CommandBus factory, set up mapping of commands and handlers and the rest is pretty much the business logic of the application.

Happy hackin’!

P.S.: I’m trying out this new way of providing code samples by using diffs, so it’s easier to follow what changed where. Let me know how it looks, thanks!

Tags: command bus, container, php, tactician, zend expressive, zf.
Categories: Development, Programming.

Need help on your PHP projects? Let's talk!

Unit testing Zend Framework 2 modules

by Robert Basic on September 15, 2012.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Porting this blog to Zend Framework 2, I decided to write some unit tests as well, while I’m at it. Not that the current code base doesn’t have unit tests, just it doesn’t have much of it… Anyway, I’d like to show how to get unit tests for modules up and running, as well how to throw in Mockery in the mix, as it can help us greatly with mocking out objects. Some of the parts shown here probably could be written in a more cleaner/nicer way, especially the autoloading bit, but so far it works for me.

The phpunit.xml file is rather simple:

<phpunit bootstrap='./bootstrap.php' colors='true'>
    <testsuite name='ZF2 Module Test Suite'>
        <directory>.</directory>
    </testsuite>
    <filter>
        <whitelist>
            <directory suffix='.php'>../src/</directory>
        </whitelist>
    </filter>
    <listeners>
        <listener class="\Mockery\Adapter\Phpunit\TestListener"
            file="Mockery/Adapter/Phpunit/TestListener.php"></listener>
    </listeners>
</phpunit>

The Mockery TestListener, as I found out the hard way, is needed for Mockery to work properly. You might add in some more stuff, like generating code coverage reports, and the like.

In the bootstrap.php we set up the autoloading for the modules, the ZF2 library, and Mockery:

<?php
putenv('ZF2_PATH=' . __DIR__ . '/../../../vendor/ZF2/library');
include_once __DIR__ . '/../../../init_autoloader.php';
set_include_path(implode(PATH_SEPARATOR, array(
    '.',
    __DIR__ . '/../src',
    __DIR__ . '/../../SomeRequiredModule/src',
    __DIR__ . '/../../../vendor',
    get_include_path(),
)));
spl_autoload_register(function($class) {
    $file = str_replace(array('\\', '_'), DIRECTORY_SEPARATOR, $class) . '.php';
    if (false === ($realpath = stream_resolve_include_path($file))) {
        return false;
    }
    include_once $realpath;
});
$loader = new \Mockery\Loader;
$loader->register();

It assumes that the currently tested module lives inside a ZF2 application. If not, you’ll probably need to adjust the paths accordingly. It also assumes that the Mockery files are in the vendor/ directory.

Testing the service layer

Don’t want to get into a fight about terminology, but the service layer for me, is the layer that lives between the controller layers and the database layers. It allows for keeping other layers clean of business logic, and easier testing. These services implement the Zend\ServiceManager\ServiceLocatorAwareInterface, which greatly simplifies unit testing, as it is easier to replace concrete objects with mocks.

Let’s assume that we have a “post” service, which we can use to get the recent posts. The post service itself does not interact with the databse, but calls an AbstractTableGateway which does all the database work. A test case for this post service, to avoid database calls, should mock the AbstractTableGateway, and use the ServiceManager to replace the concrete implementation with the mock object. An example test case for this post service could look something like this:

<?php
namespace BlogModule\Service;
use PHPUnit_Framework_TestCase as TestCase;
use Zend\ServiceManager\ServiceManager;
use Zend\Db\ResultSet\ResultSet;
use \Mockery as m;
class PostTest extends TestCase
{
    protected $postService;
    /**
    * @var Zend\ServiceManager\ServiceLocatorInterface
    */
    protected $serviceManager;
    public function setup()
    {
        $this->postService = new Post;
        $this->serviceManager = new ServiceManager;
        $this->postService->setServiceLocator($this->serviceManager);
    }
    public function testGetRecentPosts()
    {
        $mock = m::mock('Blog\Model\Table\Post');
        $this->serviceManager->setService('blogModelTablePost', $mock);
        $result = array(
            array(
                'id' => 1,
                'title' => 'Foo',
            ),
        );
        $resultSet = new ResultSet;
        $resultSet->initialize($result);
        $mock->shouldReceive('getRecentPosts')
            ->once()
            ->andReturn($resultSet);
        $posts = $this->postService->getRecentPosts();
        $this->assertSame($posts, $resultSet);
    }
}

On line 18 we set the service manager to be used with the post service, on line 22 we create a mock object, and on line 23 we set that mock object in the service manager. We set some expectations on the mock object - what method should be called, how many times and what should it return. Finally we call the actual method that is being tested on the post service and assert that the returned result is correct.

Testing the database layer

For testing the database layer, that is the AbstractTableGateway implementations, I use a little… trick. I don’t actually test what is returned from the database, but that the correct Sql\Select objects are being called, with the correct parameters in a correct order. This, in turn, means that I trust the underlying Zend\Db code that in the end, it will assemble the correct SQL queries, but I also don’t have to bother with setting up a test database, and also the tests run faster, as they don’t actually call the database. An example test case, continuing our example of getting recent posts:

<?php
namespace Blog\Model\Table;
use PHPUnit_Framework_TestCase as TestCase;
use Zend\ServiceManager\ServiceManager;
use Zend\Db\Sql\Select;
use \Mockery as m;
class PostTest extends TestCase
{
    protected $postTable;
    protected $select;
    protected $tableName = 'blog_posts';
    public function setup()
    {
        $adapter = $this->getAdapterMock();
        $this->postTable = new Post($adapter);
        $this->select = m::mock(new Select($this->tableName));
        $this->postTable->setSelect($this->select);
    }
    public function testGetRecentPosts()
    {
        $this->select->shouldReceive('from')
            ->once()
            ->with($this->tableName)
            ->andReturn($this->select);
        $this->select->shouldReceive('where')
            ->once()
            ->with(array('published = ?' => 1))
            ->andReturn($this->select);
        $this->select->shouldReceive('order')
            ->once()
            ->with('id DESC')
            ->andReturn($this->select);
        $this->select->shouldReceive('limit')
            ->once()
            ->with(10)
            ->andReturn($this->select);
        $this->postTable->getRecentPosts();
    }
}

Here we create a mock adapter (the getAdapterMock method can be seen in this gist), and use that mock adapter in our AbstractTableGateway implementation. We also create a mock Sql\Select object and we set expectations on that mock Select object. As I said, this way of testing might not be the best way out there, but it did help me catch a bug where I failed to add the where clause on the actual Select object. Yey for Mockery! Oh, and please do note that the adapter mock might not work in all cases, but again, so far it worked nicely for me.

One other thing would probably be interesting to show how to test, and that’s the action controllers, but I haven’t got around to write any controllers yet, so I’ll probably leave that for part 2. Or you could do it for homework.

Happy hackin’!

Tags: mockery, modules, testing, unit test, zend framework 2, zf.
Categories: Development, Programming, Software.

Need help on your PHP projects? Let's talk!

Working with custom view helpers in Zend Framework 2

by Robert Basic on September 11, 2012.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Zend Framework hit a big milestone as version 2 was released last week. Sadly, I didn’t have time to contribute to it, or even to poke around it much. I decided to slowly, as time permits, port this blog to ZF2; it should be a good enough learning playground.

I took the skeleton application, made it even skinnier by throwing out some (for me) unneeded parts and just put it all besides my old ZF1 code. Note: I think it could be possible to have a ZF1 and a ZF2 app run side by side, something like Stefan did for Symfony1 and Symfony2. Need to investigate on this. The first problem I ran into was using custom view helpers, especially view helpers that are more general and don’t fit into one specific module. Where to put the code? How to access them in views? The second problem was how to access the service manager from a view helper? And the third problem was how to tell the helper to use a specific value when inside a specific module?

Custom view helpers

As I found out, custom view helpers can live in different places (at least two) - in the vendor/ directory, or in the module/ directory as a part of a module. Both ways are probably good solutions, but for me it’s way easier to use the custom view helpers when they are “packaged” as a module:

On the image you can see I put the helpers in a module called Hex. The module.config.php file is something like:

<?php
return array(
    'view_helpers' => array(
        'invokables' => array(
            'customHelper' => 'Hex\View\Helper\CustomHelper',
            // more helpers here ...
        )
    )
);

The Module.php file is completely basic, it just has the Module class, implementing the getConfig() and the getAutoloaderConfig() methods. Include the module in the application’s main configuration file (config/application.config.php) and now the customHelper can be simply called from the view files as:

<php echo $this->customHelper(); ?>

Service manager in a view helper

To access the service manager in a view helper, it needs to implement the ServiceLocatorAwareInterface and two methods, setServiceLocator() and getServiceLocator(). In code, this would be something like:

<?php
namespace Hex\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class CustomHelper extends AbstractHelper implements ServiceLocatorAwareInterface
{
    /**
     * Set the service locator.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return CustomHelper
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }
    /**
     * Get the service locator.
     *
     * @return \Zend\ServiceManager\ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
    public function __invoke()
    {
        $serviceLocator = $this->getServiceLocator();
        // use it at will ...
    }
}

Now, if you call getServiceLocator(), you’ll actually get the Zend\View\HelperPluginManager which gives access to other view helpers. If you want to access the “application wide” service locator, you need to call getServiceLocator() again on the HelperPluginManager. Confused yet?

<?php
// first one gives access to other view helpers
$helperPluginManager = $this->getServiceLocator();
// the second one gives access to... other things.
$serviceManager = $helperPluginManager->getServiceLocator();

Module specific values in view helpers

The problem (a bit simplified): how to tell the view helper to show “Welcome to my site!” on all routes/modules, except for the blog module, where it should show “Welcome to my blog!”. This one was the trickiest, as it can be solved in way too many ways. I first tried 2-3 different approaches, but they either didn’t work at all, or were just plain ugly hacky solutions. The final solution came to me when I answered a different question: what would be the easiest way to unit test this code? First, the custom view helper:

<?php
namespace Hex\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Greeter extends AbstractHelper implements ServiceLocatorAwareInterface
{
    protected $message = null;
    /**
     * Set the service locator.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return CustomHelper
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }
    /**
     * Get the service locator.
     *
     * @return \Zend\ServiceManager\ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
    public function setMessage($message)
    {
        $this->message = $message;
        return $this;
    }
    public function getMessage()
    {
        if ($this->message === null) {
            // for example, get the default value from app config
            $sm = $this->getServiceLocator()->getServiceLocator();
            $config = $sm->get('application')->getConfig();
            $this->setMessage($config['message']);
        }
        return $this->message;
    }
    public function __invoke()
    {
        $message = $this->getMessage();
        return $message;
    }

And the blog module specific part, where we hook to the “preDispatch” event:

<?php
namespace Blog;
class Module
{
    public function onBootstrap($e)
    {
        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach('dispatch', array($this, 'preDispatch'), 100);
    }
    public function preDispatch($e)
    {
        $matchedRoute = $e->getRouteMatch()->getMatchedRouteName();
        // check for the matched route
        // and change the greeter message if needed
        if ($matchedRoute == 'blog') {
            $moduleConfig = $this->getConfig();
            $sm = $e->getApplication()->getServiceManager();
            $helper = $sm->get('viewhelpermanager')->get('greeter');
            $helper->setMessage($moduleConfig['message']);
        }
    }

And that would be it. I think.

Happy hackin’!

Tags: custom, php, view helpers, zend framework 2, zf.
Categories: Development, Programming, Software.

Need help on your PHP projects? Let's talk!