zf2 controller factory serviceLocator

时间:2016-04-06 05:44:27

标签: php zend-framework2 service-locator

我正在尝试将服务管理器注入控制器。

实际错误:

  

\厂商\ zendframework \ Zend的-的ServiceManager \ SRC \异常\ ServiceLocatorUsageException.php:34

     

服务“Project \ Service \ ProjectServiceInterface”已被请求插入“Zend \ Mvc \ Controller \ ControllerManager”类型的管理器,但无法检索。   在此过程中引发了先前的“Zend \ ServiceManager \ Exception \ ServiceNotFoundException”类型的异常。   顺便说一下,在父服务定位器“Zend \ ServiceManager \ ServiceManager”中找到了名为“Project \ Service \ ProjectServiceInterface”的服务:您是否忘记在您的服务器中使用$ parentLocator = $ serviceLocator-> getServiceLocator()工厂代码?

过程如下:

class BaseController extends AbstractActionController implements ServiceLocatorAwareInterface
{

    public function __construct(\Zend\ServiceManager\ServiceLocatorInterface $sl)
    {
        $this->serviceLocator = $sl;
    }
}
  1. 创建控制器并使用构造函数方法
  2. 将此BaseController扩展为AdminController
  3. 将路线设置为AdminController => /admin
  4. 使用Module.php

    public function getControllerConfig()

  5. 使用close作为工厂来创建注入serviceLocator的控制器对象

      

    'Project \ Controller \ Project'=>功能($ sm){                       $ serviceLocator = $ sm-> getServiceLocator();                       返回new \ Project \ Controller \ ProjectController($ serviceLocator);                   },

  6. 尝试使用$this->getServiceLocator()->get('service_name')
  7. 发现缺少服务的例外情况.....
  8. 现在的问题是:

    /**
     * 
     * @param ServiceLocatorInterface $sl
     */
    public function __construct(\Zend\ServiceManager\ServiceLocatorInterface $sl)
    {
        $rtn = $sl->has('Project\Service\ProjectServiceInterface');
        echo '<br />in Constructor: '.__FILE__;var_dump($rtn);
        $this->serviceLocator = $sl;
    }
    public function getServiceLocator()
    {
        $rtn = $this->serviceLocator->has('Project\Service\ProjectServiceInterface');
        echo '<br />in getServiceLocator: '.__FILE__;var_dump($rtn);
        return $this->serviceLocator;
    }
    

    __构造函数()中,服务 IS FOUND 。在 getServiceLocator() 方法中,具有相同名称的服务 未找到 ....

      构造函数中的

    :Project \ Controller \ BaseController.php   布尔(真)   在getServiceLocator中:Project \ Controller \ BaseController.php   布尔(假)

    我错过了什么吗? SharedServiceManager在这里做了些什么吗?

    本练习的全部目的是由于以下信息:

      

    不推荐使用:ServiceLocatorAwareInterface已弃用,将在3.0版中与ServiceLocatorAwareInitializer一起删除。 ...

3 个答案:

答案 0 :(得分:2)

如果你真的需要ServiceLocator,你必须用工厂注入它 像这样的东西

<强>控制器:

<?php
namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\ServiceManager\ServiceLocatorInterface;

class BaseController extends AbstractActionController
{
    protected $serviceLocator = null;

    public function __construct(ServiceLocatorInterface $serviceLocator)
    {
        $this->setServiceLocator($serviceLocator);
    }

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
}

<强>工厂:

<?php
namespace Application\Controller\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Controller\BaseController;

class BaseControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator);
    {
        $controller = new BaseController($serviceLocator->getServicelocator());
        return $controller;
    }
}

?>
module.config.php中的

<?php
// ...

    'controllers' => [
        'factories' => [
            'Application\Controller\BaseController' => 'Application\Controller\Factory\BaseControllerFactory',
            // ...
        ],
// ...

答案 1 :(得分:1)

在Zend Framework 2中,有多个服务定位器(docs here),一个通用(主要用于您自己的服务),一个用于控制器,一个用于视图助手,一个用于验证器,...具体的也称为插件管理员

您收到的错误消息只是告诉您使用了错误的服务定位器,即检索控制器的服务定位器而不是通用控制器。它还建议你如何解决你的问题:

  

您是否忘记在工厂代码中使用$ parentLocator = $ serviceLocator-&gt; getServiceLocator()

可能发生的事情(不是100%肯定)是在构造函数中传递一般服务管理器的实例,并且一切正常。然后,由于控制器实现ServiceLocatorAwareInterface,控制器服务定位器将注入您的控制器,覆盖您之前定义的那个。

此外,我认为,在版本ServiceLocatorAwareInterface中删除3的决定是因为您没有在控制器中注入服务定位器,而是直接注入控制器的依赖关系。

答案 2 :(得分:1)

您应该尝试阻止在控制器中注入服务管理器或服务定位器。将实际依赖项(在您的情况下为'Project\Service\ProjectServiceInterface')直接注入到类的__construct方法中会更好。 构造函数注入 (依赖项通过类构造函数提供) 在ZF2中被视为最佳实践

这种模式可以防止控制器在没有依赖项的情况下被实例化(它会引发错误)。

如果您注入ServiceLocatorServiceManager,您将从中解析类中的实际依赖项,那么不清楚该类实际需要什么。您最终可能会遇到一个缺少依赖项的类实例,这些依赖项本来就不应该创建。您需要在类中进行自定义检查以查看实际的依赖项是否可用,如果缺少则抛出错误。您可以使用构造函数依赖关系模式来阻止编写所有这些自定义代码。

另一个问题是,对您的课程进行单元测试比较困难,因为您无法轻松 为各个依赖项设置模拟

详细了解如何将依赖关系[{3}}注入类似问题。

更新

关于您遇到的问题。控制器类实现ServiceLocatorAwareInterface,并且在构造控制器类期间,ControllerManager在类中注入ServiceLocator。发生这种情况in my answer。就像@marcosh在他的回答中已经提到的那样,这可能是你注入的不同的服务定位器。在此injectServiceLocator方法中,您还可以找到您在问题中提到的弃用声明。

您可以使用__construct方法,因为那时(构建类之后)变量尚未被覆盖。稍后当您尝试使用getServiceLocator方法访问它时,它会被覆盖。