0

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?

Luke
  • 20,878
  • 35
  • 119
  • 178

3 Answers3

2

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

Amin Arab
  • 530
  • 4
  • 19
  • I understand this and factory is not the solution (in my opinion). The question is; how do I set up the configuration so that I can describe a service and then inject that service into another service. You like, how Spring framework bean wiring works? – Luke Mar 15 '14 at 06:06
  • in zend , i don't see something link bean-appcontext.xml but may exist but every where you have serviceLocator you can access to your service . – Amin Arab Mar 15 '14 at 06:08
  • if you want different file for each use case that you can be define all beans of use case in same place . you can load file in factory include __DIR__ . '/config/usecase-appcontext.php' but PHP isn't J2EE . – Amin Arab Mar 15 '14 at 06:34
  • Amin. I appreciate your input but this is going nowhere. The Spring bean reference is only an example of a "technique" I'm after. I want to define a service and then inject that service definition into another service. – Luke Mar 15 '14 at 08:54
  • i think you can use it : https://github.com/fezfez/ServiceLocatorFactory . but any where you access to service locator , you can access to your services that are registered and point is you can access servicelocator anywhere . – Amin Arab Mar 15 '14 at 09:17
0

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');
        //...
      }
    }
Amin Arab
  • 530
  • 4
  • 19
  • Amin. Again, thanks for your input but you don't seem to understand the question. Please stop posting answers. – Luke Mar 15 '14 at 22:30
0

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.

merlin
  • 122
  • 2
  • 6
  • Sorry. The question isn't about factories at all, it's about the configuring the service manager to allow it to inject one service definition into another. – Luke Mar 15 '14 at 22:32