Luke
Luke

Reputation: 21286

Zend Framework 2 Service Manager Dependency Injection

My application is a collection of POPO's and I'm trying to wire these POPO's up using the Zend Framework 2 Service Manager.

To illustrate my problem, take the following example:

$config = array(
   'services' => array(
      'my.app.serviceA' => new \My\App\Services\ServiceA(),
      'my.app.serviceB' => new \My\App\Services\ServiceB(),

      'my.app.manager.task' => new \My\App\Manager\TaskManager(),
   ),

);

My TaskManager class looks something like this:

class TaskManager {

   protected $serviceA;
   protected $serviceB;

   public function setServiceA( \My\App\Service\ServiceA $serviceA )
   {
      $this->serviceA = $serviceA;
   }

   public function setServiceB( \My\App\Service\ServiceB $serviceB )
   {
      $this->serviceB = $serviceB;
   }

}

As you can see, the TaskManager class has dependencies on both ServiceA and ServiceB. How do inject those services into my.app.manager.task using the Service Manager configuration using the service names defined for both ServiceA and ServiceB?

UPDATE:

I'm beginning to believe that I shouldn't be using the ServiceManager component for my purposes at all but that I should be using the Zend DI component instead.

I get the impression that the ServiceManager is a ZF2 "framework" component whereas Zend\DI seems to be more of a generic all purpose DiC. Hence, this might be the reason of ServiceManager's tied relationship with the MVC and ModuleManager components (which also seem to be "framework" components).

Maybe someone could clarify?

Upvotes: 0

Views: 2656

Answers (3)

merlin
merlin

Reputation: 122

for me, the best way is to create a class factory and use the factoryInterface, like this :

 return array(

    'service_manager' => array(
        'factories' => [
            'Task' => 'Application\TaskFactory',
        ],
        'invokables' => array(
            'Task'=> 'Application\Task',
            'ServiceA'=> 'Application\ServiceA',
            'ServiceB' => 'Application\ServiceB'
        )
    ),
);

And a factory class :

class TaskFactory implements FactoryInterface {

    /** @var  ServiceLocatorInterface $serviceLocator */
    var $serviceLocator;

    public function createService(ServiceLocatorInterface $serviceLocator) {
        $sl = $this->serviceLocator = $serviceLocator;

        // you can get your registered services
        $serviceA = $sl->get('ServiceA');
        $serviceB = $sl->get('ServiceB');


        // You can build your class using the class loader
        $task = new Application\Task();

        // Or the Service Locator Again
        $task = $sl->get('Task');

        return $task;
    }
}

You can implement the factory interface on your Task class. I prefer to have control on what I'm building.

Upvotes: 0

Amin Arab
Amin Arab

Reputation: 530

in Controller ;

$yourService = $this->getServiceLocator()->get('your_service_alias');

in View Helper : you should send in from Module.php by constructor of viewHelper

    public function getViewHelperConfig() {
        return array(
            'factories' => array(
                'loginHelper' => function($sm) {
                    return new LoginHelper($sm);
                }
        )
   }

in a calss

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
    public class UseCaseBO implements ServiceLocatorAwareInterface {
      protected $serviceLocator;

      public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
        $this->serviceLocator = $serviceLocator;
      }

      public function getServiceLocator() {
        return $this->serviceLocator;
      }

      // now instance of Service Locator is ready to use
      public function someMethod() {
        $table = $this->serviceLocator->get('your_service_alias');
        //...
      }
    }

Upvotes: 0

Amin Arab
Amin Arab

Reputation: 530

in module.config.php The Service Manager can be configured in 7 different ways:

return array(

    // instantiate the class for you when needed
    'invokables' => array(
        'commentController' => '\Comment\Controller\CommentController';
    ),

    // Aliasing a name to a known service name
    'aliases' => array(
        'Comment\Service' => 'commentService';
    ),

    // configure the instance of the object
    'factories' => array(
        'commentController' => function ($sm) {
            $locator = $sm->getServiceLocator();
            $controller = $locator->get('commentController');
            $controller->setCommentService($locator->get('Comment\Service'));
            return $controller;
        }
    ),

    // register already instantiated objects
    'services' => array(
        'commentController' => new \Comment\Controller\CommentController(),
    ),

    //factory instance that can create multiple services based on the name supplied to the factory.
    'abstract_factories' => array(
        'SomeModule\Service\FallbackFactory',
    ),

    // initialize the service whenever service created
    'initializers' => array(
        function ($instance, $sm) {
            if ($instance instanceof \Comment\Controller\CommentController){
                $instance->setCommentService($sm->get('Comment\Service'));
            }
        }
    ),

    // indicating whether or not a service should be shared
    'shared' => array(
        'commentController' => false,
    ),
);

and in Module.php

public function getControllerConfig() {
    return array(
        'factories' => array(
            'commentController' => function ($sm) {
                $controller = new \Comment\Controller\CommentController();
                $locator = $sm->getServiceLocator();
                $controller->setCommentForm($locator->get('commentForm'));
                $controller->setCommentService($locator->get('commentService'));
                return $controller;
            }
        )
    );
}

and simple use in controller :

 $commentService = $this->serviceLocator->get('Comment\Service');

you put this in getter or in init() method ZF2's New Controller::init() :: phly, boy, phly

Upvotes: 2

Related Questions