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!

Original source