2013-02-16 154 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; 
    } 
} 

正如你所看到的,我需要$服务定位 - >我的ControllerFactory中的getServiceLocator(),但不是在我的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 2013-10-22 18:32:00

+1

@Leven就是YUML – Ocramius 2013-10-22 19:43:40

3

Denitively你shouln't使用getServiceLocator因为该方法不ServiceLocatorInterface定义,而不是使用get()

5

,你可以看到我需要$ serviceLocator-> getServiceLocator()在我的ControllerFactory中,但不是在我的ServiceFactory中。为什么?

控制器工厂由不同的服务管理器实例(“ControllerLoader”)调用到主控制器工厂。这是为了使调度员不能导致主服务管理器实例化任意类。

因此,当您想要检索'greetingService'时,控制器工厂的$ serviceLocator不是您需要的那个,因为'greetingService'已在主服务管理器中注册。为了从控制器获得主服务器管理器,您使用getServiceLocator(),并且您现在拥有一个可从中获得()的问候服务的主服务管理器实例

这被称为“对等”。即“ControllerLoader”服务管理器(通过config中的'controllers'键或者Module类中的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,然后是SetServiceLocator方法的ServiceManager。

我只想使用ControllerManger及其方法获取ServiceManager然后实例化我的工厂;

部分在我的module.config.php

现在,我可以使用类似下面来筛选合适的服务定位...但我使用尽可能少的锅炉板作为的粉丝必要...

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

    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); 
} 
相关问题