Я действительно запутался в том, когда использовать 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' ), )
Буду признателен за разъяснения 🙂
Хорошего дня!
Метод 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):
Как вы можете видеть, мне нужен $ serviceLocator-> getServiceLocator () в моей ControllerFactory, но не в моем ServiceFactory. Зачем?
Заводский контроллер вызывается другим экземпляром служебного менеджера («ControllerLoader») на главный. Это значит, что диспетчер не может создать произвольный класс, созданный главным диспетчером сервиса.
В результате, $ serviceLocator контроллера factory не тот, который вам нужен, когда вы хотите получить «greetingService», поскольку «greetingService» зарегистрирован в главном сервис-менеджере. Чтобы получить главного диспетчера сервера из контроллера один, вы используете getServiceLocator (), и теперь у вас есть экземпляр главного диспетчера служб, из которого вы можете получить () «услугу приветствия»,
Это называется «пиринг». т.е. диспетчер службы «ControllerLoader» (тот, который настроен с помощью ключа «контроллеры» в конфигурации или getControllerConfiguration () в классе модуля) настроен с основным диспетчером службы как одноранговый узел.
В Denitively вы не используете getServiceLocator
так как этот метод не определен в ServiceLocatorInterface
вместо этого используйте get()
Я предлагаю это в качестве альтернативы, которая использует базовую установку 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
module.config.php { ... 'service_manager' => 'abstract_factories' => array( 'Zend\Log\LoggerAbstractServiceFactory', ), 'factories' => array( 'entities_service' => 'Service\Providers\Entities', ), 'invokables' => array( 'post' => 'Service\Controllers\Runtime\Post', ), ), }
Теперь я мог бы использовать что-то вроде следующего, чтобы отфильтровать правильный ServiceLocator … но я поклонник использования как можно меньше плиты котла по мере необходимости …
interface AbstractFactoryInterface { public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); }