I'm using Apigility, built on ZF2. Once request is dispatched to the controller's action, I need to choose proper adapter to hanle request - based on incomming parameters.
Normally, Controller is instantiated by ControllerFactory
, where you can provide all dependencies, let say I need som kind of mapper class to be injected. It's easy, if I know, which one I will use in within the controller. It's problematic if I need to let controller decide which mapper to use.
Let's say user is requesting something like getStatus
with param 'adapter1'
and another user is accessing same action, but with param 'adapter2'
.
So, I need to inject adapter1
mapper OR adapter2
mapper, which has similar interface, but different constructor.
What's the proper way how to handle this situation ?
On possible solution is to supply some kind of factory method, which will provide requested adapter, but - using the SM int the model class should be avoided.
Another way is to use SM directly in within Controller's action, but this in not best approach, because I can't reuse 'switch-case' logic for another actions / controllers.
How to handle this, please ?
You could use controller plugins for this.
Like that you can get the adapter inside your controller when you need it without injecting a ServiceManager
and without adding all the logic to the factory. The adapter will only be instantiated when you request it in your controller action method.
First you need to create your controller plugin class (extending Zend\Mvc\Controller\Plugin\AbstractPlugin
):
<?php
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class AdapterPlugin extends AbstractPlugin{
protected $adapterProviderService;
public function __constuct(AdapterProviderService $adapterProviderService){
$this->adapterProviderService = $adapterProviderService;
}
public function getAdapter($param){
// get the adapter using the param passed from controller
}
}
Then a factory to inject your service in the class:
<?php
namespace Application\Controller\Plugin\Factory;
use Application\Controller\Plugin\AdapterPlugin;
class AdapterPluginFactory implements FactoryInterface
{
/**
* @param ServiceLocatorInterface $serviceController
* @return AdapterPlugin
*/
public function createService(ServiceLocatorInterface $serviceController)
{
$serviceManager = $serviceController->getServiceLocator();
$adapterProvicerService = $serviceManager>get('Application\Service\AdapterProviderService');
return new AdapterPlugin($adapterProviderService);
}
}
Then you need to register your plugin in your module.config.php
:
<?php
return array(
//...
'controller_plugins' => array(
'factories' => array(
'AdapterPlugin' => 'Application\Controller\Plugin\Factory\AdapterPluginFactory',
)
),
// ...
);
Now you can use it inside your controller action like this:
protected function controllerAction(){
$plugin = $this->plugin('AdapterPlugin');
// Get the param for getting the correct adapter
$param = $this->getParamForAdapter();
// now you can get the adapter using the plugin
$plugin->getAdapter($param);
}
Read more on controller plugins here in the documentation