Caching your ZF2 merged configuration

19th June 2013

Zend Framework 2's ModuleManager has the ability to cache the merged configuration information for your application. This is very useful as it allows you to separate out your configuration within the config/autoload directory into logical files without worrying about the performance implications of lots of files.

Enabling caching is simply a case of setting these configuration keys in config/application.config.php within the module_listener_options section:

	'module_listener_options' => array(
        'config_cache_enabled'     => true,
        'module_map_cache_enabled' => true,
        'cache_dir'                => 'data/cache/',
		// other keys go here (e.g. module_paths & config_glob_paths)
	),

This then creates the cache files data/cache/module-classmap-cache.php and data/cache/module-config-cache.php and you're done. If you need to regenerate the files, simply delete then.

During development this can be a pain to remember!

We can solve this by only caching when in production. The easiest way to do this is by setting an environment variable in your virtual host. For Apache, use SetEnv; you're on your own for any other web server.

The way I do this is to modify config/application.config.php like this:

use Zend\Stdlib\ArrayUtils;
 
$config = array(
	// all standard application configuration ...
);
 
 
$localAppConfigFilename = 'config/application.config.' . getenv('APPLICATION_ENV') . '.php';
if (is_readable($localAppConfigFilename)) {
    $config = ArrayUtils::merge($config, require($localAppConfigFilename));
}
 
return $config;

I then create a separate configuration file for each environment. For production, I turn on caching:

config/application.config.production.php:

return array(
    'module_listener_options' => array(
        'config_cache_enabled' => true,
        'module_map_cache_enabled' => true,
    ),
);

and for my local development, I add some development modules:

config/application.config.development.php:

return array(
    'modules' => array(
        'BjyProfiler',
        'ZendDeveloperTools',
    ),
);

This system allows me to have a faster production site and specific modules loaded when developing that make life easier.

Contracts and NDAs for Nineteen Feet

15th June 2013

Now that I have my own business, I've become an avid listener to the Unfinished Business podcast presented by Anna Debenham and Andy Clarke. From the first episode, they have emphasised the importance of having a contract and, in a recent episode, why an NDA is a good idea.

I don't know about you, but when I hear the words "contract" and "NDA", the word "incompressible" comes to mind and I was not enthused at all about sorting these out for Nineteen Feet. Fortunately, Andy feels the same way and very generously shared the contract and NDA that he uses on his blog. The relevant articles are: Contract Killer and Three Wise Monkeys.

If you're starting or have just started your own web business, go and read those two articles now!

I haven't modified Andy's origin documents that much, but as a backend developer rather than a designer, some bits were less relevant to me and I wanted to add a clause about termination and about licensing the source code. I also altered the NDA slightly to make it fit onto one page. I also changed "trash" to "bin"!

Here are my versions of Andy's documents:

I hope you find them useful.

Injecting configuration into a ZF2 controller

30th April 2013

One thing you may find yourself needing to do is access configuration information in a controller or service class.

The easiest way to do this is to use the ServiceManger's initialiser feature. This allows you to write one piece of injection code that can be applied to multiple objects. It's easier to show this in action!

Let's assume that we have this configuration file:

config/autoload/global.php:

return array(
    'application' => array(
        'setting_1' => 234,
    )
);

That is, we have a key called 'application' that contains application-specific configuration that we would like to access in our controllers (or service classes).

Firstly we define a interface, ConfigAwareInterface:

module/Application/src/Application/ConfigAwareInterface.php:

namespace Application;
 
interface ConfigAwareInterface
{
    public function setConfig($config);
}

We can now add this to a controller:

module/Application/src/Application/Controller/IndexController.php:

namespace Application\Controller;
 
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\ConfigAwareInterface;
 
class IndexController extends AbstractActionController
    implements ConfigAwareInterface
{
    protected $config;
 
    public function setConfig($config)
    {
        $this->config = $config;
    }
 
    // action methods, etc.
}

In the controller, we add a use statement, implement our interface and the required setConfig() method.

Finally, we add an initializer to the Module class:

module/Application/Module.php:

class Module
{
    // Other methods, such as OnBoostrap(), getAutoloaderConfig(), etc.
 
    public function getControllerConfig()
    {
        return array(
             'initializers' => array(
                function ($instance, $sm) {
                    if ($instance instanceof ConfigAwareInterface) {
                        $locator = $sm->getServiceLocator();
                        $config  = $locator->get('Config');
                        $instance->setConfig($config['application']);
                    }
                }
            )
        );
    }
}

(We also have a use Application\ConfigAwareInterface; statement at the top!)

As getControllerConfig() is used by a specific ServiceManager only for controllers, we need to retrieve the main ServiceManager using getServiceLocator() in order to collect the merged configuration. As we only want the settings from within the 'application' key, we only pass that into the controller's setConfig() method.

The configuration settings are now available to us in any controller that implements ConfigAwareInterface.

We can also do this for service classes - we simply add another initalizer to the Module:

module/Application/Module.php:

    public function getServiceConfig()
    {
        return array(
             'initializers' => array(
                function ($instance, $sm) {
                    if ($instance instanceof ConfigAwareInterface) {
                        $config  = $sm->get('Config');
                        $instance->setConfig($config['application']);
                    }
                }
            )
        );
    }

It also follows that you can use initializers for any type of generic injection, such as mappers, db adapters, loggers, etc. Simply create an interface and write an initalizer.

Adding Diff syntax highlighting to Sublime Text

26th April 2013

My chosen colour scheme for Sublime Text doesn't include support for diff/patch files, so I added my own.

To the bottom of my .tmTheme file, I added this just above the closing </array>:

        <dict>
            <key>name</key>
            <string>diff.header</string>
            <key>scope</key>
            <string>meta.diff, meta.diff.header</string>
            <key>settings</key>
            </dict><dict>
                <key>foreground</key>
                <string>#009933</string>
            </dict>
 
        <dict>
            <key>name</key>
            <string>diff.deleted</string>
            <key>scope</key>
            <string>markup.deleted</string>
            <key>settings</key>
            </dict><dict>
                <key>foreground</key>
                <string>#DD5555</string>
            </dict>
 
        <dict>
            <key>name</key>
            <string>diff.inserted</string>
            <key>scope</key>
            <string>markup.inserted</string>
            <key>settings</key>
            </dict><dict>
                <key>foreground</key>
                <string>#3333FF</string>
            </dict>
 
        <dict>
            <key>name</key>
            <string>diff.changed</string>
            <key>scope</key>
            <string>markup.changed</string>
            <key>settings</key>
            </dict><dict>
                <key>foreground</key>
                <string>#E6DB74</string>
            </dict>

This sets up a green colour for the meta information, blue for added lines, red for deleted lines and a yellowish colour for changed.

Simple logging of ZF2 exceptions

24th April 2013

I recently had a problem with a ZF2 based website where users were reporting seeing the error page displayed, but I couldn't reproduce in testing. To find this problem I decided to log every exception to a file so I could then go back and work out what was happening. In a standard ZF2 application, the easiest way to do this is to add a listener to the 'dispatch.error' event and log using Zend\Log.

To do this, I started with the Application's Module class and added an event listener:

    public function onBootstrap($e)
    {
        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach('dispatch.error', function($event){
            $exception = $event->getResult()->exception;
            if ($exception) {
                $sm = $event->getApplication()->getServiceManager();
                $service = $sm->get('Application\Service\ErrorHandling');
                $service->logException($exception);
            }
        });
    }

This code attaches an anonymous function to the 'dispatch.error' event which retrieves the exception from the event's result and passes it to the logException() method in an ErrorHandling class. We retrieve ErrorHandling from the service manager which allows us to inject an instance of Zend\Log into it:

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Application\Service\ErrorHandling' =>  function($sm) {
                    $logger = $sm->get('Zend\Log');
                    $service = new ErrorHandlingService($logger);
                    return $service;
                },
                'Zend\Log' => function ($sm) {
                    $filename = 'log_' . date('F') . '.txt';
                    $log = new Logger();
                    $writer = new LogWriterStream('./data/logs/' . $filename);
                    $log->addWriter($writer);
 
                    return $log;
                },
            ),
        );
    }

There's obviously a few use statements at the top of the file for this to work:

use Application\Service\ErrorHandling as ErrorHandlingService;
use Zend\Log\Logger;
use Zend\Log\Writer\Stream as LogWriterStream;

The logging itself is done within the ErrorHandling class:

namespace Application\Service;
 
class ErrorHandling
{
    protected $logger;
 
    function __construct($logger)
    {
        $this->logger = $logger;
    }
 
    function logException(\Exception $e)
    {
        $trace = $e->getTraceAsString();
        $i = 1;
        do {
            $messages[] = $i++ . ": " . $e->getMessage();
        } while ($e = $e->getPrevious());
 
        $log = "Exception:\n" . implode("\n", $messages);
        $log .= "\nTrace:\n" . $trace;
 
        $this->logger->err($log);
    }
}

The logException method simply creates a string containing the exception's message along with any previous exception messages and the trace. We then call the Log's err method to store the log and can peruse at our leisure.

Update: I have updated the logException method to use a do..while() loop as it's neater and doesn't cause a an out-of-memory error that the previous code did. That is, it's a good idea to reuse the same variable when calling getPrevious()!