2013-02-16 2 views
9

Я действительно смущен, когда следует использовать getServiceLocator, а когда нет. В качестве примера:ZF2 когда использовать getServiceLocator(), а когда не

+ Module 
-+ Helloworld 
--+ src 
---+ Controller 
----+ IndexController.php 
----+ IndexControllerFactory.php 

---+ Service 
----+ LogginService.php 
----+ GreetingService.php 
----+ GreetingServiceFactory.php 

GreetingServiceFactory.php имеет содержание:

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

И IndexControllerFactory.php имеет содержание:

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

Как вы можете видеть, что мне нужно $ ServiceLocator -> getServiceLocator() в моей ControllerFactory, но не в моем ServiceFactory. Зачем? Оба используют один и тот же интерфейс ServiceLocatorInterface, который даже не определяет метод getServiceLocator().

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

Я бы признателен за любые разъяснения :)

имеют хороший день!

ответ

20

Метод getServiceLocator определяется на AbstractPluginManager, так как он реализует ServiceLocatorAwareInterface. Как указывал Maks3w, он не является частью ServiceLocatorInterface, поэтому не используйте его при внедрении фабрики услуг.

Вы можете в любом случае определить ваш завод, как закрытие и до сих пор используют его:

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

В то время как в этом примере $pm действительно ServiceLocatorInterface экземпляр, вам все равно нужно получить ссылку на «основной» сервис-менеджер для доступа к 'greetingService'.

ZF2 использует разные менеджеры по обслуживанию или администраторы плагинов для контроллеров, служб, помощников просмотра, плагинов контроллеров и т. Д. Это в основном для типа-намекания (посмотрите на интерфейс AbstractPluginManager, чтобы понять, как достигается строгость типа) и для обеспечения безопасности.

В этом случае проблема безопасности не разрешает доступ к службам, которые не являются контроллерами, особенно с маршрутами с динамическим параметром controller. Вот почему контроллеры хранятся в отдельном диспетчере подключаемых модулей.

Поскольку диспетчер плагинов контроллера создан из «главного» сервис-менеджера, он также инициализируется с помощью ServiceLocatorAwareInterface.

Чтобы сделать это более ясным, я добавил граф отношений (не включает в себя завод и не принимают его как действительный UML):

Pseudo-UML

+1

Какой инструмент вы использовали для создания этой диаграммы? Выглядит круто. – Leven

+1

@Leven это YUML – Ocramius

3

Denitively вы shouln't использовать getServiceLocator, поскольку этот метод не определен в ServiceLocatorInterface использовать вместо get()

5

Как вы можете см., мне нужно $ serviceLocator-> getServiceLocator() в моей ControllerFactory, но не в моем ServiceFactory. Зачем?

Завод-изготовитель вызывается другим экземпляром служебного менеджера («Контроллер-загрузчик») на главный. Это значит, что диспетчер не может создать произвольный класс, созданный главным диспетчером сервиса.

В результате поставщик $ serviceLocator на заводе-изготовителе контроллера не тот, который вам нужен, когда вы хотите получить «greetingService», поскольку «greetingService» зарегистрирован в главном сервисном менеджере. Чтобы получить главного диспетчера сервера с контроллера один, вы используете getServiceLocator(), и теперь у вас есть экземпляр главного сервисного менеджера, из которого вы можете получить() «приветствие»

Это называется «пиринг». то есть диспетчер услуг «ControllerLoader» (тот, который настроен с помощью ключа «контроллеры» в конфигурации или getControllerConfiguration() в классе модуля) настроен с основным диспетчером службы как одноранговый узел.

0

Я предлагаю это в качестве альтернативы, которая использует установку базовой module.config.php

Теперь я делаю что-то подобное, но используя что-то вроде этого.

class BaseServices extends AbstractActionController 
implements ServiceLocatorAwareInterface{ 
    ... 
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator){ 
     if($serviceLocator instanceof ControllerManager){ 
      $this->service_locator = $serviceLocator->getServiceLocator(); 

      $this->entities_service = $this->service_locator 
      ->get('entities_service'); 

      $this->session = new Session(array(
      'entities_service'=>$this->entities_service, 
      'service_locator'=>$this->service_locator, 
     )); 
      return $this; 
     } 
     } 
    } 
... 
} 

Теперь вещь, которая меня в тупик было того, чтобы прийти к осознанию того, что мне нужно использовать только первый локатор сервиса, который используется во время создания экземпляра любого контроллера, который расширяет этот класс ...

По инстанцированию: этот класс был сначала загружен ControllerManager, а затем ServiceManager для метода setServiceLocator.

Я только хотел использовать ControllerManger и его метод для получения ServiceManager для создания экземпляров моих заводов;

парциальное на моем module.config.php

Теперь я мог бы использовать что-то вроде следующего для фильтрации правой ServiceLocator ... еще я фанат использования в качестве маленького котла пластины, как необходимо ...

interface AbstractFactoryInterface 
{ 
    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); 

    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); 
}