Reputation: 15
Im new to Zend 2 and have this situation. Would like to know whats the best way to handle the situation.
Inside the Application module i have these classes
namespace Application\Foo;
class Base {
protected $this->services; //service locator
public function myFunc() {
//needs service locator here
$this->services;
}
}
namespace Application\Foo;
class A extends Base {
//can have some method that uses $this->services;
}
namespace Application\Foo;
class B extends Base {
}
As you can see i need the service locator inside my Base class. and then i want to use the A,B... extended classes in my controllers.
Thanks in advice
Update
According to jmleroux's suggestion i updated the code to look like this
namespace Application\Foo;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Base implements ServiceLocatorAwareInterface {
protected $this->services; //service locator
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->services = $serviceLocator;
}
public function getServiceLocator() {
return $this->services;
}
public function myFunc() {
//needs service locator here
$this->services;
}
}
module.conf.php
service_manager => array(
'invokables' => array(
'my_ser' => 'Application\Foo\Base'
)
)
in my controller
$this->serviceLocator->get('my_ser');
returns the base class with service locator loaded
now my question is how to get my extended classes(A, B...) with the service locator loaded. since
$x = new \Application\Foo\A();
does not have the service locator loaded. do i have to add all my extended classes to module config as invokables? or is there a better alternative.
Thanks again.
Update 2
Thanks all (@jmleroux specially) for the support. Found these solutions and im adding them here thinking it will help some one else
NOTE: Just a general idea. namespaces and class names are not accurate
Solution 1 (recommended) - with ServiceLocatorAwareInterface / ServiceLocatorAwareTrait for php 5.4+
each class implements ServiceLocatorAwareInterface and add it to the service manager
namespace Application\Foor;
class A implements ServiceLocatorAwareInterface {
protected $services;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->services = $serviceLocator;
}
public function getServiceLocator() {
return $this->services;
}
}
class B implements ServiceLocatorAwareInterface {
use ServiceLocatorAwareTrait;
}
module.conf.php (or inside the Module getServiceConfig() function )
'service_manager' => array(
'invokables' => array(
'my_ser_a' => 'Application\Foo\A',
'my_ser_b' => 'Application\Foo\B',
......
)
)
call the service by name inside controllers
Solution 2 - with AbstractFactoryInterface
create a factory class
class MyFac implements AbstractFactoryInterface {
public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
if (class_exists($requestedName)){ \\eg. check Application\Foo\A exists
return true;
}
return false;
}
public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
$class = new $requestedName; \\eg. creates an instance of Application\Foo\A
$class->setServiceLocator($locator); \\make sure your class has this method
return new $class;
}
}
module.conf.php (or inside the Module getServiceConfig() function )
'service_manager' => array(
'abstract_factories' => array(
'Application\Foo\MyFac'
)
)
in controllers call
$this->getServiceLocator()->get('Application\Foo\A');
Thanks.
Upvotes: 0
Views: 1640
Reputation: 947
In order to access the service locator, your base class need to be declared as an invokable service implementing ServiceLocatorAwareInterface.php
If you are on PHP 5.4+, you can use ServiceLocatorAwareTrait.php
Upvotes: 2