ZF2 when to use getServiceLocator() and when not to
frameworks, php, service-locator, zend-framework2
Solution
The method `getServiceLocator` is defined on the `AbstractPluginManager`, since it implements the `ServiceLocatorAwareInterface`. As Maks3w pointed out, it is not part of the `ServiceLocatorInterface`, so avoid using it when implementing a service factory.
You can anyway define your factory as closure and still use it:
class MyModule
{
public function getControllerConfig()
{
return array(
'factories' => array(
'IndexController' => function (
\Zend\ServiceManager\AbstractPluginManager $pm
) {
$ctr = new IndexController();
$ctr->setGreetingService(
$pm
->getServiceLocator()
->get('greetingService')
);
return $ctr;
},
),
);
}
}
While in this example `$pm` is indeed a `ServiceLocatorInterface` instance, you will still need to get a reference to the "main" service manager to access the `'greetingService'`.
ZF2 uses different service managers or plugin managers for controllers, services, view helpers, controller plugins, etc... That is mainly for type-hinting (look at the interface of the `AbstractPluginManager` to understand how type strictness is achieved) and for security.
In this case, the security issue is disallowing access to services that are not controllers, especially with routes with a dynamic `controller` parameter. That's why controllers are kept in a separate plugin manager.
Since the controller plugin manager is created from the "main" service manager, it also is initialized thanks to the `ServiceLocatorAwareInterface`.
To make this more clear, I've added a graph of the relations (does not include the factory and don't take it as valid UML):
Problem
I am really confused on when to use getServiceLocator and when not to. As an example: ``` + Module -+ Helloworld --+ src ---+ Controller ----+ IndexController.php ----+ IndexControllerFactory.php ---+ Service ----+ LogginService.php ----+ GreetingService.php ----+ GreetingServiceFactory.php ``` GreetingServiceFactory.php has the content: ``` <?php namespace Helloworld\Service; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class GreetingServiceFactory implements FactoryInterface { public function createService (ServiceLocatorInterface $serviceLocator) { $greetingService = new GreetingService(); $greetingService->setEventManager($serviceLocator->get('eventManager')); $loggingService = $serviceLocator->get('loggingService'); $greetingService->getEventManager()->attach('getGreeting', array( $loggingService, 'onGetGreeting' )); return $greetingService; } } ``` And IndexControllerFactory.php has the content: ``` <?php namespace Helloworld\Controller; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class IndexControllerFactory implements FactoryInterface { public function createService (ServiceLocatorInterface $serviceLocator) { $ctr = new IndexController(); $ctr->setGreetingService($serviceLocator->getServiceLocator() ->get('greetingService')); return $ctr; } } ``` As you can see, I need $serviceLocator->getServiceLocator() in my ControllerFactory but not in my ServiceFactory. Why? Both use the same interface ServiceLocatorInterface which does not even define the getServiceLocator() method. module.config.php: ``` 'controllers' => array( 'factories' => array( 'Helloworld\Controller\Index' => 'Helloworld\Controller\IndexControllerFactory' ) ) , 'service_manager' => array( 'invokables' => array( 'loggingService' => 'Helloworld\Service\LoggingService' ), 'factories' => array( 'greetingService'=> 'Helloworld\Service\GreetingServiceFactory' ), ) ``` I'd appreciate any clarification :) Have a nice day!