Внедрение зависимостей диспетчера служб Zend Framework 2

Мое приложение представляет собой набор POPO, и я пытаюсь связать эти POPO с помощью Zend Framework 2 Service Manager.

Чтобы проиллюстрировать мою проблему, возьмем следующий пример:

$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(),
   ),

);

Мой класс TaskManager выглядит примерно так:

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;
   }

}

Как видите, класс TaskManager имеет зависимости как от ServiceA, так и от ServiceB. Как внедрить эти службы в my.app.manager.task с помощью конфигурации Service Manager, используя имена служб, определенные как для ServiceA, так и для ServiceB?

ОБНОВЛЕНИЕ:

Я начинаю думать, что вообще не должен использовать компонент ServiceManager для своих целей, а вместо этого должен использовать компонент Zend DI.

У меня сложилось впечатление, что ServiceManager является компонентом «каркаса» ZF2, тогда как Zend\DI кажется более универсальным DiC для всех целей. Следовательно, это может быть причиной связанных отношений ServiceManager с компонентами MVC и ModuleManager (которые также кажутся компонентами «фреймворка»).

Может быть, кто-нибудь прояснит?


person Luke    schedule 15.03.2014    source источник


Ответы (3)


в module.config.php Диспетчер служб можно настроить 7 различными способами:

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,
    ),
);

и в модуле.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;
            }
        )
    );
}

и простое использование в контроллере:

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

вы помещаете это в геттер или в метод init() Новый контроллер ZF2: :init() :: фли, мальчик, флай

person Amin Arab    schedule 15.03.2014
comment
Я понимаю это, и фабрика - это не решение (на мой взгляд). Вопрос в том; как мне настроить конфигурацию, чтобы я мог описать службу, а затем внедрить эту службу в другую службу. Вам нравится, как работает связывание компонентов Spring framework? - person Luke; 15.03.2014
comment
в zend я не вижу какой-либо ссылки bean-appcontext.xml, но может существовать, но везде, где у вас есть serviceLocator, вы можете получить доступ к своей службе. - person Amin Arab; 15.03.2014
comment
если вам нужен другой файл для каждого варианта использования, вы можете определить все компоненты варианта использования в одном месте. вы можете загрузить файл на заводе, включая DIR . '/config/usecase-appcontext.php', но PHP не J2EE. - person Amin Arab; 15.03.2014
comment
Амин. Я ценю ваш вклад, но это никуда не денется. Ссылка на бин Spring — это только пример метода, который мне нужен. Я хочу определить службу, а затем внедрить это определение службы в другую службу. - person Luke; 15.03.2014
comment
я думаю, вы можете использовать его: github.com/fezfez/ServiceLocatorFactory. но в любом месте, где вы получаете доступ к сервисному локатору, вы можете получить доступ к своим зарегистрированным сервисам, и дело в том, что вы можете получить доступ к сервисному локатору в любом месте. - person Amin Arab; 15.03.2014

в контроллере;

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

в View Helper: вы должны отправить из Module.php конструктором viewHelper

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

в классе

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');
        //...
      }
    }
person Amin Arab    schedule 15.03.2014
comment
Амин. Еще раз, спасибо за ваш вклад, но вы, кажется, не понимаете вопроса. Пожалуйста, прекратите публиковать ответы. - person Luke; 16.03.2014

для меня лучший способ - создать фабрику классов и использовать factoryInterface, например:

 return array(

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

И заводской класс:

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;
    }
}

Вы можете реализовать фабричный интерфейс в своем классе Task. Я предпочитаю контролировать то, что я строю.

person merlin    schedule 15.03.2014
comment
Извиняюсь. Вопрос вовсе не о фабриках, а о настройке диспетчера служб, чтобы он мог вводить одно определение службы в другое. - person Luke; 16.03.2014