Zend Framework 2 : using PSR-4 autoloader in your Module
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.
The 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 :
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
I’ve been using this module layout style for a long time, but I’m using a base class for the modules like this:
Which ist then subclassed like this:
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.
great! you’re welcome 😉
Very clear and helpful example. Thank you!
Hi,
I followed your tutorial, precise and clear but i get following error:
Fatal error: Uncaught exception ‘Zend\ModuleManager\Exception\RuntimeException’ with message ‘Module (Foo) could not be initialized.’ in /var/www/vhosts/leveninternet.com/httpdocs/site-previews/zendapp/zf2-tutorial/vendor/zendframework/zendframework/library/Zend/ModuleManager/ModuleManager.php on line 189
Any suggestions ?
check vendor/composer/autoload_psr4.php and see if the namespace defined in there