Zend Framework 2 Modules – The Application’s Heart

Zend Framework 2 Modules - The Application's Heart

Zend Framework 2 Modules - The Application's Heart

If I have seen further it is by standing on the shoulders of giants.

It’s a really exciting time at the moment with Zend Framework 2 gaining so much traction, after being stable for some time now.

Though I and countless others really enjoyed the 1.x series, it did leave some things to be desired – to be fair.

But the more I explore of the 2.x series, the more I honestly can say that I’m very impressed with it. It may not be as fast as the previous series, but with respect to development, there’s so much going for it it’s worth shouting about.

So it really is rewarding and exciting to begin covering all that it has to offer us. In part one of this series, I looked at a central concept of the revised framework – Dependency Injection.

In this, the second part, I’m moving on to give a good introduction to the next most important aspect – Modules.

In today’s post, we’ll be looking at what they are, some thoughts and quotes from the key developers involved and working code to get you started.

How The Developers Describe It

Quoting directly from the manual, here, in a nutshell, is what you can expect from 2.x Module.

Zend Framework 2.0 introduces a new and powerful approach to modules. This new module system is designed with flexibility, simplicity, and re-usability in mind. A module may contain just about anything: PHP code, including MVC functionality; library code; view scripts; and/or public assets such as images, CSS, and JavaScript.

Want another take on it? Matthew Weier O’Phinney says it most succinctly on his blog:

In ZF2, a module is simply a namespaced directory, with a single “Module” class under it; no more, and no less, is required.

And here’s the description from the Modules author himself, Evan Coury:

A re-usable piece of functionality that can be used to construct a more complex application.

What Are Modules

Modules are comprised of three key concepts:

  • The Module Autoloader – a specialized autoloader that is responsible for the locating and loading of modules’ Module classes from a variety of sources.
  • The Module Manager – takes an array of module names and fires a sequence of events for each one
  • ModuleManager Listeners – Event listeners can be attached to the module manager’s various events

I’m not going to do you the injustice of parroting the manual; but instead say it as I understand it. In the 1.x series, an application could be seen as a series of, at least partially, coupled components.

The 2.x series breaks from that dynamic and supports a true inter-relation of uncoupled modules. Each of the modules can stand alone, be designed to work together cohesively, or be the application all in and of itself. This is made possible through the 3 previously mentioned components.

For the best example of this working, checkout the excellent and rapidly growing ZF Modules project. It’s still a fairly new project, but you can see that as new as it is, there’s likely a module to suit your needs.

For example:

Each module that you write, can, if desired, provide its own views, layouts, images, css and javascript files, and anything else that it needs.

Or, it can make use of other modules – so that you only write the minimal amount of code that’s required.

A Simple Example

Now, that’s my simplistic explanation of the new modules system in ZF2. Let’s work through some code and see how to create one.

Using the recommended structure for a ZF2 module, create a new directory under the module directory, that you’ll find when you start with the Zend Skeleton application.

I’ve created one and called it Generic. There’s no special reason for this name, other than to make it clear it’s mine. Under that, create a new file called Module.php.

This is the Bootstrap file that you would have been used to in the 1.x series. It’s just about as simple as the previous approach. All it needs to contain is the following:

namespace Generic;
class Module
{    
}

That’s it. With that, you have a functioning module. Note that you need to use PHP namespaces when working with ZF2.

Everything under your module will need to respect that when it’s developed. Namespaces aren’t the only change you need to be aware of. For more, check out the next section.

Now I said that the module in its current form will function – but it won’t be loaded. For that, you need to add your module to /config/application.config.php. My version, from the Zend Skeleton application looks as follows:

return array(
    'modules' => array(
        'Application',
        'Generic'       // << My Generic Module
    ),
    'module_listener_options' => array(
        'config_glob_paths'    => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
        'module_paths' => array(
            './module',
            './vendor',
        ),
    ),
);

You can see that it has two key array keys: modules and module_listener_options. If your module’s namespace isn’t listed in modules, then the Module Autoloader will not load it. This may seem a bit confusing coming from the 1.x series. But it makes sense.

If you’d like a really good understanding behind the reasons why modules aren’t autoloader, check out this post from ZF project lead Matthew Weier O’Phinney.

I’ll sum it up by saying that, it’s a good approach to take. Consider the following scenarios:

  • There are problems with the module
  • You need to make changes to it
  • It’s just not ready for prime-time yet
  • Having it be auto-enabled, then have to be disabled (and possibly be overlooked)

Configuration Paths

In the module_listener_options array key, you’ll see:

'config_glob_paths'    => array(
    'config/autoload/{,*.}{global,local}.php',
),

What this does is to tell the ModuleManager which configurations to compile together in to the aggregate configuration for the application.

So if/when you create a config directory in your module and add in the standard module.config.php, then its configuration will be merged with the other modules in the application.

Important Functions

getConfig

Now, the module configuration that I’ve covered so far is the stock one. It’s made possible by the following function in Module.php:

public function getConfig()
{
    return include __DIR__ . '/config/module.config.php';
}

It returns an array or Traversable object that contains the environment delineated configuration for your application, i.e., production, staging, development etc.

In it you can include a number of configurations areas, such as dependency injection, routing, views and more.

getAutoloaderConfig

Now, you have to make sure that the Module Autoloader can make best use of your module implement the getAutoloaderConfig function.

This informs the Module Autoloader where to find the required classes. Here’s the stock function that I’ve used:

public function getAutoloaderConfig()
{
    return array(
        'Zend\Loader\ClassMapAutoloader' => array(
            __DIR__ . '/autoload_classmap.php',
        ),
        'Zend\Loader\StandardAutoloader' => array(
            'namespaces' => array(
                __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
            ),
        ),
    );
}

The Remaining Module Structure

Now what I’ve covered so far is a basic module. There are a few other directories that you’ll likely use

src

Under source are all the PHP files for your application. Similar in style to the 1.x series it can also include directories for:

  • Controller – All your modules controller files with the accompanying actions
  • Form – All your form objects
  • Model – All your database objects

view

All of your view templates, in directories that match the controller names in the module and with names that match the controller actions. Not much different from 1.x.

test

This is, in my not so humble opinion, a very welcome inclusion in 2.x. I felt so often that testing was really an after thought previously?

Despite there being a lot of documentation around, there always seemed to be problems getting it started, consistency in the information provided or gaps in what was written.

I’ve followed along with the manual and am very happy to say that it worked first time for me, no issues and no hassles whatsoever. It was a real pleasure to see how easy and integral it was.

Nothing gives more confidence than solid tests when developing applications. Right?

language

Unless you’re developing a very specific application, the possibility of not localising or internationalising it is very slim. So, like testing, localisation is baked in, right from the get go.

If you’re getting started with the skeleton application, which I strongly suggest you do, you’ll see it contains an Application module that has it’s language directory pre-populated with PO and MO files for a wide assortment of languages.

Don’t worry if you’re not too familiar with it, grab a copy of Poedit for your platform and open up one of them and you’ll see the base language and translation side by side – ready for you to add to or modify.

Other Essentials

autoload_classmap.php

You may be familiar with an option in the 1.x series that allowed you to compile a class list so that it didn’t have be searched on every invocation.

Well, an even better setup is integrated in to the 2.x series. Under your module, you can add a file, called autoload_classmap.php.

In that, you return a list of classes in a manner compliant with the new ZF2 autoloader. For my, Generic, module it returns an empty array as I have no production concerns to be worries about.

However, you can use the built in classmap_generator.php script to do this. You’ll find it in the /bin directory of the ZF2 source.

For a good understanding of the new autoloader, check out the great post by Rob Allen.

module_paths

As you may have seen in the code snippet above, there was an array key called module_paths in the configuration returned from application.config.php.

This is part of what makes the new module structure so flexible. The directories specified there are the paths that the Module Autoloader searches when loading modules.

So, if you want to stick with the recommended structure, then keep ‘./module’ in there. If you want to go with a different structure, change the name. I like the configuration provided.

You keep your modules under ./modules and add 3rd party libraries under ./vendor. That way you know what’s yours and what’s external.

It’s a simple approach which I believe will pay off big maintenance dividends down the track in a project. Tell me I’m not right about that one!

Key Points To Be Aware Of

Though all this change is very exciting, please be aware that you can’t just make a simple transition to the 2.x series. The 2.x series takes a lot of the PHP 5.3 advancements in to account.

To make a smooth transition as possible ensure that you’re all over the following concepts:

  • Namespaces
  • Closures / Anonymous Functions

Further Reading

In Conclusion

So, there you have it. I hope you enjoyed this introduction to one of the key aspects of Zend Framework 2 – the ModuleManager. Through the definition of it, seeing what some of the core developers have said and the working code example, I’m confident that you’ll be able to get up and running with it very quickly.

I Didn’t Cover Everything

Please don’t feel cheated with this introduction. To be honest, there’s a hell of a lot that can be involved in making full use of the new Modules system, despite what I said at the start.

My aim here was to give you a simple and effective introduction that we can build on progressively.

Over to You

Do you see it as the improvement it is, over the 1.x series? Are there any points that you feel were missed? Tell me in the comments?

Intermediate Tutorial
  • Pingback: Einführung ind Zend Framework 2 Module - Zend Framework Magazin

  • ChristofCoetzee

    I worked with Zend Framework 1 (which had its pitfalls), recently started learning ZF2, I must say the two versions are worlds apart and I’m super amazed by the power and potential locked up in ZF2 especially the modules as you’ve stated.

    • http://www.matthewsetter.com/ maltblue

      @ChristofCoetzee hi Christof, I couldn’t agree more. Though I enjoyed ZF1 quite a lot, it just doesn’t compare to ZF2. And that’s from not being an expert (yet). My favourite so far are modules and the EventManager. But there’s so much to choose from. What features are you using most, so far?

  • dsame

    ZF2 is a sample of the good idea implemented with bad tools.
     
    The module system makes me to cry. A lot of lines to type here and there, a lot of places to make typos and mistakes, unpredictable reaction on mistakes, the ambiguity of the docs and  redundancy of the code. Configs,.. configs,.. configs,.. And nothing is working as expected. Even the samples just hung and returns 500 error code without any tracebacks and error messages.
     
    ZF was hard to debug, ZF2 is not usable at all.

    • http://www.matthewsetter.com/ maltblue

      @dsame I appreciate that ZF2 (and ZF1 for that reason) weren’t necessarily perfect, and often times required more than their fair share of work, once running, they were pretty much a dream to maintain. It’s true that the new approach, using dependency injection and the various managers definitely involves a learning curve. But from my own experience, it ends up being simpler, not harder. Do you want a hand to debug some code that you’ve been writing?

      • dsame

        @maltblue It will be maintenance nightmare to find the places where the endless services/locators/managers are configured among endless set of config files.
         
         To add a controller requires to modify 3 files. To add DB driven model requires modifications of uncountable number of files.
         
        They borrowed J2EE patterns without the understanding the tool java-developers have, and made us to handcode the zillions of lines intended to be generated by Java IDEs.

        • http://www.matthewsetter.com/ maltblue

          @dsame I thought the same thing originally, but the more that I looked at it, to a point, the simpler it’s become. The primary files that I look at are the main config and the respective module config files.
           
          I appreciate there’s quite a number of spots – no sense denying it. During a recent project I became frustrated enough to tweet asking about when there will be more tooling support available via zftool.
           
          ezimuel was kind enough to reply saying that, whilst not ready yet, much more advanced tooling was planned and currently under development.