I am building a module in zend-framework2. I want to access ServiceLocator
in constructor of Controller class.
public function __construct() {
var_dump($this->getServiceLocator()->get('Config'));
}
But it gives following error.
Call to a member function get() on a non-object
When I tried to get this in Action, It works perfect -
public function inAction() {
$sm = $this->getServiceLocator();
$config = $sm->get('Config');
}
What is the correct way to get ServiceLocator
in constructor?
At the time of the construction of a class, the dependency of the ServiceLocator
is not yet injected. This happens after that through initializers.
The workflow is like that:
- controller called "My\Controller\FooController"
- resolve string to classname
- $ctrl = new FooController(); // This is where __construct() is called
if $ctrl instanceof AbstractActionController
$ctrl->setServiceLocator($serviceLocator);
endif
- return $ctrl;
The easiest workaround is to write yourself a lazy getter function inside your controller:
protected $config;
public function getConfig() {
if (null === $this->config) {
$this->config = $this->getServiceLocator()->get('config');
}
return $this->config;
}
This approach will work and you'll be happy. However you should know that this isn't actually best practice, since you call a dependency from another dependency. A better way would be to actually inject the config into your controller.
public function __construct(array $config) {
$this->config = $config;
}
And the instead of an invokable
you write a factory
. This is done at best in the getControllerConfig()
function of your Module
-Class
public function getControllerConfig() {
return array(
'factories' => array(
'My\Controller\FooController' => function($cpm) {
$sl = $cpm->getServiceLocator();
return new FooController(
$sl->get('config')
);
}
)
);
}
And then the config will be injected into your controller and it will also be available inside your __construct()
in case you wanna cut out specific parts of the whole config.