Friday, November 16, 2012

How to test a Zend Framework 2 Application

A Zend Framework 2 application has a couple of test suites. First of all, it contains Zend Framework 2 including its test suite. Then you have also your own module (or modules) which can contain its own test suites. Last but not least, you could have additional thirdparty modules (f.e. DoctrineORMModule or DoctrineModule) and thirdparty libraries (f.e. Symfony\Console, Doctrine\ORM, Doctrine\Common), which contain its own test suites.
To run all test suites for your application, you need to install phpunit and it's dependencies, then you need to run something like this:
phpunit -c vendor/zendframework/zendframework/tests/phpunit.xml
phpunit -c vendor/doctrine/common/phpunit.xml
phpunit -c modules/Application/tests/phpunit.xml
...

Well, of course you can create a simple bash script, that does the job for you. But if you want to exclude disable modules, that won't work. You have to change the script each time, you disable or install a module.

The solution: Humus PHPUnit Module

Humus PHPUnit Module is a Module for Zend Framework 2 for unit testing. It is able to test all your zf2 modules and libraries at once.

The installation is quite easy:


And you DON'T have to have phpunit installed at all! HumusPHPUnitModule will install EHER/PHPUnit through composer and you have phpunit installed in your vendor directory.

Usage is easy, too:
./vendor/bin/humusphpunit

How it works:
You have two possibilities, to enable a test suite for the humus phpunit module.
1) Using HumusPHPUnitModule\ModuleManager\Feature\PHPUnitProviderInterface
<?php

namespace MyModule;

use HumusPHPUnitModule\ModuleManager\Feature\PHPUnitProviderInterface;

class Module implements PHPUnitProviderInterface
{
    public function getPHPUnitXmlPaths()
    {
        return array(
            dirname(dirname(__DIR__)) . '/tests/phpunit.xml'
        );
    }
}

You can implement the PHPUnitProviderInterface in your own modules and provide an array of phpunit.xml files. The PHPUnit Runner collects them and runs all of them. To run the tests for thirdparty modules, that are independent from HumusPHPUnitModule, you can either write your own module, that returns phpunit.xml files for every thirdparty module you have (this can be one module per thirdparty-lib, but also a single one returning an array including all phpunit.xml files for all your thirdparty modules. Another way is using the configuration file.

2) Using configuration
<?php
return array(
    'humus_phpunit_module' => array(
        'phpunit_runner' => array(
            'Doctrine\Common' => array(
                'vendor/doctrine/common/phpunit.xml.dist'
            )
        )
    )
);

Just put this in your application configuration and run the bin script (./vendor/bin/humusphpunit).
That's all, there is also a HumusPHPUnitSampleApp - This is a demo application to show the features of Humus PHPUnit Module. It tests a sample application module with the PHPUnitListener and the Doctrine\Common lib and Zend Framework 2 with configuration.

Friday, October 12, 2012

When migration to Zend Framework 2 seems impossible

The problem

When you got a really big codebase and lots of developers working on it, releasing new features and bugfixes every 2-3 weeks, it seems impossible to migrate to Zend Framework 2, soon.
That's because you can't stop further development, you have customers waiting for the new features, they wait for bugfix releases, to get stuff running, that's buggy, you have more than 1mio lines of code and possibly > 100 active developers on that codebase. How can you migrate? I stombled accross this problem already when the first ZF2 betas came out and startet to write some code that should solve the problem.
The result is HumusMvc, it integrates Zend Framework 2's ModuleManager and ServiceManager in a ZF1 application.

The migration path

First of all, you create a new skeleton for you application. Simply clone the HumusMvcSkeletonApplication and use it as base for you skeleton app.
At the next step, you create a repository per module you have in your old ZF1 application. Put the source code in the "src/" directory of that module, create a Module.php file, name the Module, put the module configuration in it, etc. - in other words, create a simple ZF2 module out of your ZF1 application module. If you use HumusMvcAssetManager, too, you can also provide a public directory in your module and use the asset manger. That way you can override assets in a very similar way you override view scripts in a ZF1 application.

The module now can look something like this:
- MyAppDefaultModule/
    - config/
        - module.config.php
    - layouts/
    - public/
        - css/
        - js/
        - img/
    - src/
        - controllers/
        - models/
        - views/
    - tests/
    - autoload_classmap.php
    - composer.json
    - Module.php

If you use ZF1 with the Resource-Autoloader, than you don't have psr-0 compliant classnames, so define your autoloading simply with classmap autoloader.
In order to install your module, just require it with composer.

In your module.config.php you provide your front_controller configuration, you have to tell the front controller, that you have a module, where it can dispatch.

<?php
return array(
    'front_controller' => array(
        'controller_directory' => array(
            'default' => __DIR__ . '/../src/controllers'
        ),
    )
);


You can now define some resources with ZF2's service manager in your module config file. You can remove those resources from bootstrapping later. HumusMvc ships with Navigation, Translator and Locale factories, so you don't need to handle these, just configure them.
If you have something like a db connection, that was bootstrapped in your old application, you need to do this again. Therefore you use the "onBootstrap" event. Well, you could define everything right now with the service manager, but that is exactly that much work, we wanted not to do now, because that would stop the further development for quite a time.

MyAppDefaultModule\Module.php
    /**
     * Listen to the bootstrap event
     *
     * @param EventInterface $e
     * @return array
     */
    public function onBootstrap(EventInterface $e)
    {
        $application = $e->getParam('application');
        $serviceManager = $application->getServiceManager();

        $config = $serviceManager->get('Config');

        // @todo refactor later and use cleanly service manager
        $this->setupDbConnection($serviceManager, $config);

        // we need to put config in zend_registry
        // @todo refactor later
        \Zend_Registry::set('config', new \Zend_Config($config));
    }

    protected function setupDbConnection($serviceManager, $config)
    {
        if (!isset($config['myapp']['db'])) {
            throw new \RuntimeException(
                'No multi db config found.'
            );
        }
        $options = $config['myapp']['db'];

        if (isset($options['defaultMetadataCache'])) {
            $this->setDefaultMetadataCache($options['defaultMetadataCache'], $serviceManager);
            unset($options['defaultMetadataCache']);
        }

        $adapter = $options['adapter'];
        $default = $options['default'];
        unset(
            $options['adapter'],
            $options['default']
        );

        $adapter = \Zend_Db::factory($adapter, $options);

        if ($default) {
            \Zend_Db_Table::setDefaultAdapter($adapter);
        }
    }

Here is a short example you to bootstrap db connection on every request and put the application configuration into Zend_Registry.

Further refactorings

At first, I recommend to remove all "onBootstrap" methods when neccessary and put this stuff in your service manager, so you only instantiate the objects, when they are need, not on every request.
In the next refactoring rounds, you can refactor only one module at a time, so development in the other modules can still be done. Put all stuff in the service manager and use it as a service locator inside your application. Remove Zend_Registry everywhere. When you are done with that, use a php namespacer tool (or do it by manually) and refactor to a namespaced codebase. Remember, code is per module, so you can do this step module per module. Further bugfixing and development of new features is still possible.

Final migration to Zend Framework 2

You should now have a very flexible and modern Zend Framework 1 application, that makes use of a lot of stuff from Zend Framework 2, already: Service Manager, Module Manager, Event Manager, just to name a few. You don't have any expensive upfront bootstrapping any more, you moved everything to the service manger. You should have a namespaced codebase. You use ZF 2 classes much more, than ZF1 classes. - Now it's time to do the final migration.

Refactor all controllers, refactor route configuration refactor all view scripts, and so on. Now it's time for the hard work, we skipped before - but we had a couple of month time to bring our codebase to something, that _can_ be refactored to a ZF2 codebase very fast.

Wednesday, October 10, 2012

Distinct IoC, Service Locator & Dependency Injection Container (DIC)

The dependency injection pattern - A short example

<?php

class SomeClassWithDependencies
{
    public function __construct()
    {
        $this->dependency = new SomeObject();
        $this->config = Zend_Config_Ini(
            'path/to/my/configfile.ini', 
            APPLICATION_ENV
        );
    }
}
What we see here, is a class with several dependencies: The first two obvious dependencies are "SomeObject" and "Zend_Config_Ini", but addiotional with have also the dependency to the path of the config file ("path/to/my/configfile.ini") and the APPLICATION_ENV constant. So all together we have 4 dependencies, two of them to other objects. The problem starts, when I want to extend this class or I want to write unit tests and need to mock a lot of stuff. Let's improve this example and make it DI enabled.
<?php

class SomeClassWithDependencies
{
    public function __construct(
        SomeObject $someObject,
        Zend_Config $config
    ) {
        $this->dependency = $someObject;
        $this->config = $config;
    }
}
SomeClassWithDependencies is now DI enabled code. It has no hard dependencies on a concrete instance, instead it gets its dependencies injected. The main difference is now, how you use the class. Before the refactoring, you could simply instantiate the class and work with it. No you have to do some wiring upfront.
Before:
<?php

$object = new SomeClassWithDependencies();

After:
<?php

$someObject = new SomeObject();
$config = new Zend_Config_Ini('path/to/my/configfile.ini', APPLICATION_ENV);
$object = new SomeClassWithDependencies($someObject, $config);

If you use this class a couple of times in your application, you have redundant code everywhere you instantiate the class. Imagine even how complex things can be, if we have hundreds of classes like that. Where to put the wiring? The answer is: in a inversion of control container. An inversion of control container is simple object, that creates all services for you and holds the instantiation wiring.

Dependency Injection Container (DIC)

A DIC gets configured and is able to instantiate objects from its configuration. Ralph Schindler said: "DiC's require that you meta-program. You configure it, the container does all of the new calls. This means that instead of programming, you're metaprogramming." DIC's get their configuration and additional some DIC's (like Zend_Di) have the abbilities for auto-wiring and auto-instantiation.

Service Locator

A service locator instantiates objects by calling factories or closures. It isn't able to auto-wire or auto-instantiate. It can only create, what is defined in its factories and closures. However, when the service locator doesn't get injected into an object, so that the consuming object is able the pull soft dependencies from it, it isn't a real service locator, just a simple container that produces instances by name.
Other relavant posts:
Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler
Learning about dependency injection and PHP by Ralph Schindler

Friday, September 7, 2012

Zend Framework 2.0.0 STABLE Released!

I need to post this:

Zend Framework 2.0.0

This is the first stable release of the new version 2 release branch.

04 September 2012

NEW IN ZEND FRAMEWORK 2
-----------------------

New and/or refactored components include:

- EventManager - provides subject/observer, pubsub, aspect-oriented programming,
  signal slots, and event systems for your applications.
- ServiceManager - provides an Inversion of Control (IoC) container for managing
  object life-cycles and dependencies via a configurable and programmable
  interface.
- DI - provides a Dependency Injection Container, another form of IoC.
- MVC - a newly written MVC layer for ZF2, using controllers as services, and
  wiring everything together using events.
- ModuleManager - a solution for providing plug-and-play functionality for
  either MVC applications or any application requiring pluggable 3rd party code.
  Within ZF2, the ModuleManager provides the MVC with services, and assists in
  wiring events.
- Loader - provides new options for autoloading, including standard, performant
  PSR-0 loading and class-map-based autoloading.
- Code - provides support for code reflection, static code scanning, and
  annotation parsing.
- Config - more performant and more flexible configuration parsing and creation.
- Escaper - a new component for providing context-specific escaping solutions
  for HTML, HTML attributes, CSS, JavaScript, and combinations of contexts as
  well.
- HTTP - rewritten to provide better header, request, and response abstraction.
- I18n - a brand new internationalization and localization layer built on top of
  PHP's ext/intl extension.
- InputFilter - a new component for providing normalization and validation of
  sets of data.
- Form - rewritten from the ground up to properly separate validation, domain
  modeling, and presentation concerns. Allows binding objects to forms, defining
  forms and input filters via annotations, and more.
- Log - rewritten to be more flexible and provide better capabilities
  surrounding message formats and filtering.
- Mail - rewritten to separate concerns more cleanly between messages and
  transports.
- Session - rewritten to make testing easier, as well as to make it more
  configurable for end users.
- Uri - rewritten to provide a cleaner, more object oriented interface.

Many components have been ported from Zend Framework 1, and operate in
practically identical manners to their 1.X equivalent. Others, such as the
service components, have been moved to their own repositories to ensure that as
APIs change, they do not need to wait on the framework to release new versions.

Welcome to a new generation of Zend Framework!