Why is the Servicemanager injected in a invokable and not a service

+4 votes
asked Jan 30, 2013 by ponsjuh

I'm currently playing with the ZF2 serviceManager, and i'm trying to figure out why the serviceManager doesn't inject the sm in a class that implements ServiceLocatorAwareInterface.

My main question is am i doing it right or is the "services" key not for services that implement ServiceLocatorAwareInterface but for services that don't need injection?

in Module.php

public function getServiceConfig() {
    return array(
        'invokables' => array(
            'myService1' => 'MyModule\Service\Service'
        ),
        'services' => array(
            'myService2' => new MyModule\Service\Service(),
        ),
    );
}

in MyModule\Service\Service.php

namespace MyModule\Service;

use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;

class Service implements ServiceManagerAwareInterface
{
    /**
     * @var ServiceManager
     */
    protected $serviceManager = NULL;

    /**
     * Retrieve service manager instance
     *
     * @return ServiceManager
     */
    public function getServiceManager()
    {
        return $this->serviceManager;
    }

    /**
     * Set service manager instance
     *
     * @param ServiceManager $serviceManager
     */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;
    }
}

When i call the service in a controller

<?php

namespace MyModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{

    public function IndexAction() {

        $service1   = $this->getServiceLocator()->get('myService1');
        $sm1        = $service1->getServiceManager(); 
        //$sm1 becomes a object of Zend\ServiceManager\ServiceManager
        //In other words i now can access the SM from within my service.

        $service2   = $this->getServiceLocator()->get('myService2');
        $sm2        = $service2->getServiceManager(); 
        //$sm2 becomes NULL
        //The service isn't aware of the SM and can't access it.

    }

}

2 Answers

+5 votes
answered Jan 30, 2013 by chris-martin

You should continue to use the "invokables" section if you'd like to utilize the ServiceManagerAwareInterface and the automatic injection of the Service Manager into your service.

Looking through /Zend/ServiceManager/ServiceManager.php, "services" are meant to be registered as already instantiated objects with the ServiceManager. When the service locator looks up in it's local cache of services during retrieval, it assumes that "services" are already fully set up and does not inject the sm or run any initializers.

"invokables", "factories", "abstract_factories" are created on the fly and injects the sm when the "initializers" are run on a newly created service instance (see function create($name)).

+3 votes
answered Oct 25, 2013 by mike

Forget about getServiceConfig() and use your module config instead. It's faster and cacheable:

module.config.php:

'service_manager' => array(
    'invokables' => array(
        'MyModule\Service\Service' => 'MyModule\Service\Service',
    ),
)

MyModule\Service\Service.php:

<?php
namespace MyModule\Service;

use \Zend\ServiceManager\ServiceLocatorInterface;

class Service
{
    public function __invoke(ServiceLocatorInterface $sm)
    {
        // go bananas here :)
    }

    public functiom greet()
    {
        return 'Hello World';
    }
}

anywhere inside zend2:

<?php
    $service=$serviceManager->get('MyModule\Service\Service');
    echo $service->greet();
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...