2013-02-16 198 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); 
} 
相關問題