Controller Plugin for Configuration Array Access

Controller Plugin for Configuration Array Access

Plugin to access configuration arrays in controllers.

I use configuration arrays to keep application-wide settings in my Zend Framework applications like items_per_page to use with pagination, or secret keys, or any other variable that I don't want to keep in the database but directly in the file system.

In the beginning, I started injecting configuration array into the controllers by using controller factories. However, this requires doing the exact same thing for every single controller. Then I learned there is a better way and that's where I met Controller Plugins

Here is how I created a controller plugin I called application. Everything below is applied on a clean Zend Framework Skeleton Application.

Started with creating the folder /module/Application/src/Controller/Plugin and Application.php class module in this location. Assigning the $settings variable in the plugin constructor for now.

# /module/Application/src/Controller/Plugin/Application.php

<?php
namespace Application\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Config\Config;

class Application extends AbstractPlugin
{
    protected $settings;
    
    public function __construct()
    {
        $settings = [
            'pagination'    => [
                'itemsPerPage' => 13,
            ],
        ];
        $this->settings = new Config($settings);
    }
    
    public function getSettings()
    {
        return $this->settings;
    }
}

Now I need to introduce the plugin to my module in the module configuration file.

# /module/Application/src/config/module.config.php

<?php
namespace Application;

use Zend\ServiceManager\Factory\InvokableFactory;

return [
    // ...
    
    'controller_plugins' => [
        'aliases' => [
            'application' => Controller\Plugin\Application::class,
        ],
        'factories' => [
            Controller\Plugin\Application::class => InvokableFactory::class,
        ],
    ],    
    
    // ...
];

Note that the plugin is defined as InvokableFactory so far. I am going to change it when it is time to inject settings configuration variable via plugin's factory. Not there yet. I just have a plugin that could be called within any controller action that will return settings array defined in the plugin's constructor. It is good time to test it in the application module's IndexController.

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

<?php
public function indexAction()
{
   return new ViewModel([
      'itemsPerPage' => $this->application()->getSettings()->pagination->itemsPerPage
   ]);
}

Zend\Config\Config used in the plugin constructor helps me to use the object notation above. This way I can now use $this->itemsPerPage variable in my view script and it will return 13 as defined in the provided configuration array.

It's great but the configuration array will be actually defined in the global.php file autoloaded by my application. So I have to read it prior to creating my plugin and inject it into its constructor instead of defining directly in the constructor.

I should define the configuration array in the global.php file first.

# /config/autoload/global.php

<?php
    return [
        // ...
   	
        'application' => [
            'settings' => [
                'pagination'    => [
                    'itemsPerPage' => 13,
                ],
            ],
        ],
    	
        // ...
    ];

Whenever I need to inject something into my controllers, mappers, hydrators, and plugins, I need to create a corresponding Factory. In this case, I have to inject this configuration array defined in the global.php to my plugin. So let's create the ApplicationFactory.php file in /module/Application/src/Controller/Plugin/Factory.

# /module/Application/src/Controller/Plugin/Factory/ApplicationFactory.php

<?php
namespace Application\Controller\Plugin\Factory;

use Zend\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
use Application\Controller\Plugin\Application;

class ApplicationFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $config = $container->get('config');
        $settings = $config['application']['settings'];
        $plugin = new Application($settings);
    
        return $plugin;
    }    
}

$container reads the configuration array for me and I pull the settings array I set up in global.php then create the Application plugin by injecting in it. Finally return the $plugin.

I need to change my plugin code to accept this injected variable as $setting instead of defining it in the constructor to make it work.

# /module/Application/src/Controller/Plugin/Application.php

<?php
namespace Application\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Config\Config;

class Application extends AbstractPlugin
{
    protected $settings;
    
    public function __construct($settings)
    {
        $this->settings = new Config($settings);
    }
    
    public function getSettings()
    {
        return $this->settings;
    }
}

Finally, I need to tell my module to create the plugin by using its dedicated factory instead as an InvokableFactory.

# /module/Application/src/config/module.config.php

<?php
namespace Application;

return [
    // ...
    
    'controller_plugins' => [
        'aliases' => [
            'application' => Controller\Plugin\Application::class,
        ],
        'factories' => [
            Controller\Plugin\Application::class => Controller\Plugin\Factory\ApplicationFactory::class,
        ],
    ],    
    
    // ...
];

Factory didn't change how the plugin is used in the view script, it still provides the necessary information by using the $this->application()->getSettings()->pagination->itemsPerPage object notation. However, now the setting is in the autoloaded global.php configuration file.



Published on Nov 28, 2016