Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : using PSR-4 autoloader in your Module

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on January 11, 2014

zf2-zendframework2 This post is inspired by Phil Sturgeon blog post about Autoloading Laravel application code with PSR-4. It can be applied when you’re using Zend Framework module. Instead of using default structure, you can define the structure like this.zf2-module-with-psr-4The Classes inside Controller folder will have namespace Foo\Controller, and in the Model folder will have namespace Foo\Model.
Ok, let’s make it happen!
1. Let’s the Module::getAutoloaderConfig() function empty

//module/Foo/Module.php
namespace Foo;

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

    public function getAutoloaderConfig()
    {
    }
}

2. Configure composer.json
Add psr-4 autolaod config into your composer.json.

{
    "autoload": {
        "psr-4":{
            "Foo\\" : "module/Foo/src/"
        }
    },
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.2.5"
    }
}

3. update composer

$ php composer.phar self-update
Updating to version 69e77fbbb564e57a6c1a97eaa3c8b751bab70688.
    Downloading: 100% 

4. Run dump-autoload

$ php composer.phar dump-autoload
Generating autoload files

5. Now, You are getting new generated autoload file named vendor/composer/autoload_psr4.php automatically

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Foo\\' => array($baseDir . '/module/Foo/src'),
);

6. Perfect!, Let’s creating file for samples
a. the model class

//module/Foo/src/Model/FooModel.php
namespace Foo\Model;

class FooModel
{
    function __construct()
    {
        echo "foo";
    }
}

b. the controller class

//module/Foo/src/Controller/FooController.php
namespace Foo\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class FooController extends AbstractActionController
{
    public function indexAction()
    {
        new \Foo\Model\FooModel();
        die; //break for test
    }
}

c. the config/module.config.php

//module/Foo/config/module.config.php
return array(
    'router' => array(
        'routes' => array(
            'foo' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/foo',
                    'defaults' => array(
                        'controller' => 'Foo\Controller\Foo',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    'controllers' => array(
        'invokables' => array(
            'Foo\Controller\Foo' => 'Foo\Controller\FooController'
        ),
    ),
);

7. Register your module into config/application.config.php as usual.

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

8. Let’s call in browser : http://yourapphost/foo , if it’s working as planned, it will show us :
foo-screen-call

Done! I hope this post helpful.

References :
1. http://philsturgeon.co.uk/blog/2014/01/autoloading-laravel-application-code-with-psr4
2. https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
3. http://akrabat.com/zend-framework-2/thoughts-on-module-directory-structure/
4. http://zf2.readthedocs.org/en/latest/user-guide/modules.html

About these ads

2 Responses

Subscribe to comments with RSS.

  1. demonkoryu said, on January 21, 2014 at 4:40 pm

    I’ve been using this module layout style for a long time, but I’m using a base class for the modules like this:

    abstract class BaseModule implements AutoloaderProviderInterface
    {
        /**
         * @var string Path of current module
         */
        protected $path;
    
        /** @var string Namespace of current module */
        protected $namespace;
    
    
        /**
         * This is to be called by descendant classes with:
         * parent::__construct(__DIR__, __NAMESPACE__)
         *
         * @param $path      string Module path
         * @param $namespace string Module namespace
         */
        public function __construct($path, $namespace)
        {
            $this->path = $path;
            $this->namespace = $namespace;
        }
    
    
        public function getAutoloaderConfig()
        {
            $config = [
                'Zend\Loader\StandardAutoloader' => [
                    'namespaces' => [
                        $this->namespace => $this->path . '/src/',
                    ],
                ],
            ];
    
            return $config;
        }
    }
    

    Which ist then subclassed like this:

    class Module extends BaseModule
    {
        public function __construct()
        {
            parent::__construct(__DIR__, __NAMESPACE__);
        }
        
        /// ...
    }
    

    The advantage of this style is that there is no need to enter your module into the composer.json.

    The disadvantage of course is that there is a base class to derive from, and that the communication of intent is not as
    good as with the psr-4 composer.json entries.

    Anyway, thanks for summing this up.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 245 other followers

%d bloggers like this: