Welcome to Abdul Malik Ikhsan's Blog

Compose modular Expressive application with “ZF2 style” structure

Posted in Tutorial PHP, Zend Framework by samsonasik on December 28, 2015

expressive-modular-structure-strategy Yes, there is a doc for compose modular application in Zend\Expressive. And No, I won’t debate about how non-shareable module shouldn’t be in other modules (only “root” module), which is on personal preference. In this post, I just want to show you how to compose modular application like the “ZF2” structure, with config, view, and class that require the config per-“module”, and that’s do-able!.

Let’s do it!:

1) Same as doc, requiring mtymek/expressive-config-manager:

$ composer require mtymek/expressive-config-manager

2) Register your modules as namespace in composer autoload:

// composer.json
// ...
    "autoload": {
        "psr-4": {
            "App\\": "src/App/",
            "Album\\": "src/Album/"
        }
    },
// ...

3) Run dump-autoload

$ composer dump-autoload

4) Let’s extract one by one per-module, “App” and “Album”
a. src/App/AppConfig.php

//src/App/AppConfig.php
namespace App;

class AppConfig
{
    public function __invoke()
    {
        return include __DIR__ . '/config/expressive-config.php';
    }
}

b. src/Album/AlbumConfig.php

//src/Album/AlbumConfig.php
namespace Album;

class AlbumConfig
{
    public function __invoke()
    {
        return include __DIR__ . '/config/expressive-config.php';
    }
}

c. src/App/config/expressive-config.php
You can move various arrays from config/autoload/routes.global.php to src/App/config/expressive-config.php:

return [
    
    'dependencies' => [
        'invokables' => [
            App\Action\PingAction::class => App\Action\PingAction::class,
        ],
        'factories' => [
            App\Action\HomePageAction::class => App\Action\HomePageFactory::class,
        ],
    ],
    
    'routes' => [
        [
            'name' => 'home',
            'path' => '/',
            'middleware' => App\Action\HomePageAction::class,
            'allowed_methods' => ['GET'],
        ],
        [
            'name' => 'api.ping',
            'path' => '/api/ping',
            'middleware' => App\Action\PingAction::class,
            'allowed_methods' => ['GET'],
        ],
    ],
];

d. src/Album/config/expressive-config.php

Like App config, you can define:

return [
    
    'dependencies' => [
        'factories' => [
            Album\Action\AlbumPageAction::class => Album\Action\AlbumPageFactory::class,
        ],
    ],
    
    'routes' => [
        [
            'name' => 'album',
            'path' => '/album',
            'middleware' => Album\Action\AlbumPageAction::class,
            'allowed_methods' => ['GET'],
        ],
    ],
];

5) Templates
As in the “App” and “Album” modules, at this case, we need template, we can define templates path in the config:

a. for App config

// src/App/config/expressive-config.php
return [
    // ...
    'templates' => [
        'paths' => [
            'app'    => [ __DIR__ . '/../templates/app'],
        ],
    ], 
];

Note:
As it will redundant with “app” key registered in config/autoload/templates.global.php, you need to remove “app” key under “paths” in config/autoload/templates.global.php. Don’t forget to remove the “app” directory inside rootproject/templates to avoid confusion.

b. for Album config

// src/Album/config/expressive-config.php
return [
    // ...
    'templates' => [
        'paths' => [
            'album'    => [ __DIR__ . '/../templates/album'],
        ],
    ],
];

Now, you can have the following structure:
expressive-modular-structure-strategy-template

6) Register the “modules” in config/config.php:

use Zend\Expressive\ConfigManager\ConfigManager;
use Zend\Expressive\ConfigManager\PhpFileProvider;

$configManager = new ConfigManager([
    App\AppConfig::class,
    Album\AlbumConfig::class,
    // ...
    
    new PhpFileProvider('config/autoload/{{,*.}global,{,*.}local}.php'),
]);

return new ArrayObject($configManager->getMergedConfig());

It’s done! You can continue with writing middlewares! Tired to follow the steps? Just clone and install from here: https://github.com/samsonasik/learn-expressive-modular

Advertisements

2 Responses

Subscribe to comments with RSS.

  1. Chris said, on September 28, 2016 at 1:50 pm

    Informative tutorial! I’ve been following many of your Zend Expressive tutorials, so thanks for them; I have a question about this modular setup though. If the module configs are merged by ConfigManager, what happens if there are conflicting routes? Ie. if I have in two routes configs ‘path’ => ‘/album’ (which actually are ‘/module-one/album’ and ‘/module-two/album’ but with the module prefix removed)?

    • samsonasik said, on September 29, 2016 at 7:23 pm

      all config merged, i guest, routing that registered at last module is the one that will be used.


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

%d bloggers like this: