My question in short: Can I use a single Factory for multiple Controllers?
More details:
I have some global non-module specific settings in /config/autoload/global.php which look like this:
return array(
'settings' => array(
'setting_a' => 'foo',
'setting_b' => 'bar'
),
// More ZF default configuration ...
);
Now I want to make these settings accessable in every controller without having to call $this->getServiceLocator()->get('config')
all the time.
So my idea was to introduce a class attribute $settings
in my AbstractController
which get’s injected with the configuration array. I tried to fetch the config directly in the constructor of AbstractController
. However getServiceLocator()
doesn’t seem ready at the time and returns NULL.
I could build Controller Factories for every controller and inject the settings like this:
class ControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
return new \MyModule\Controller\MyController($config['settings']);
}
}
But it would be the same over and over again. So my question is: Can I use a single Factory for multiple controllers?
In my module.config.php I could specify a single factory class for multiple controllers:
return array(
'controllers' => array(
'factories' => array(
'MyModule\Controller\MyControllerA' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerB' => 'MyModule\Factory\ControllerFactory',
'MyModule\Controller\MyControllerC' => 'MyModule\Factory\ControllerFactory',
)
),
);
But in the factory I need to return the actual Controller object by hand (see example above) which of course only works with one Factory per Controller.
Hope, I made my problem clear.
UPDATE 2013-03-24:
Although I first followed the suggested solution by creating an initializer, I never really liked using it just for the injection of the configuration.
So I kept digging around and ended up creating a Controller plugin to receive the settings.
The code for the plugin looks like this:
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class Settings extends AbstractPlugin
{
protected $settings;
public function __invoke()
{
$config = $this->getController()->getServiceLocator()->get('Config');
if (isset($config['settings']) && is_array($config['settings'])) {
$this->settings = $config['settings'];
}
return $this->settings;
}
}
After adding the plugin in module.config.php with
'controller_plugins' => array(
'invokables' => array(
'settings' => 'My\Controller\Plugin\Settings',
)
),
I can easily access my settings within a controller by simply calling $this->settings()
. Hope this helps anyone.
You could try attaching an initializer, then as the controller is created the instance is checked against known initializers. If the instance matches a given interface or abstract class, then you can apply some common logic.
I've not tested this approach with controllers but given that the ControllerLoader is a type of ServiceManager/ServiceLocator it should in theory work.
'controllers' => array (
'initializers' => array(
'MyApplication\Controller\Initializer'
)
),
Then the Initalizer would look something like:
class Initializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof MyControllerInterface)
{
return;
}
// Do something for this instance
}
}
or even cleaner: add your controllers as invokables to the config, then do something like this which turns your controllers into one-liners:
abstract class AbstractControllerFactory implements FactoryInterface
{
protected $controllerKey;
public function createService(ServiceLocatorInterface $serviceLocator) {
$config = $serviceLocator->get('config');
$controller = $serviceLocator->get($this->controllerKey);
$controller->setConfig($config);
return $controller;
}
}
class ControllerFactory extends AbstractControllerFactory implements FactoryInterface
{
protected $controllerKey = 'mymodule_controller_mycontroller';
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With