繁体   English   中英

ZF2何时使用getServiceLocator()而何时不使用

[英]ZF2 when to use getServiceLocator() and when not to

我真的很困惑何时使用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中使用$ serviceLocator-> 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'
    ),
)

我很感激任何澄清:)

祝你今天愉快!

方法getServiceLocatorAbstractPluginManager上定义,因为它实现了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实例,但您仍需要获取对“main”服务管理器的引用以访问'greetingService'

ZF2为控制器,服务,视图助手,控制器插件等使用不同的服务管理器或插件管理器......主要用于类型提示(查看AbstractPluginManager的接口以了解如何实现类型严格性)和安全性。

在这种情况下,安全问题是禁止访问非控制器的服务,尤其是对于具有动态controller参数的路由。 这就是控制器保存在单独的插件管理器中的原因。

由于控制器插件管理器是从“主”服务管理器创建的,因此它也可以通过ServiceLocatorAwareInterface初始化。

为了更清楚,我添加了关系图(不包括工厂,不要将其作为有效的UML):

伪UML

如您所见,我需要在我的ControllerFactory中使用$ serviceLocator-> getServiceLocator(),而不是在我的ServiceFactory中。 为什么?

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

因此,当您想要检索'greetingService'时,控制器工厂的$ serviceLocator不是您需要的那个,因为'greetingService'已向主服务管理器注册。 要从控制器获取主服务器管理器,请使用getServiceLocator(),然后您将拥有主服务管理器的实例,您可以从中获取()'问候服务'

这被称为'对等'。 即,将“主要服务管理器”作为对等体设置“ControllerLoader”服务管理器(通过配置中的“控制器”键配置的服务管理器或模块类中的getControllerConfiguration())。

你不应该使用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);
} 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM