我正在尝试将服务管理器注入控制器。
实际错误:
\厂商\ 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;
}
}
BaseController
扩展为AdminController
AdminController => /admin
使用Module.php
public function getControllerConfig()
使用close作为工厂来创建注入serviceLocator的控制器对象
'Project \ Controller \ Project'=>功能($ sm){ $ serviceLocator = $ sm-> getServiceLocator(); 返回new \ Project \ Controller \ ProjectController($ serviceLocator); },
$this->getServiceLocator()->get('service_name')
现在的问题是:
/**
*
* @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一起删除。 ...
答案 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中被视为最佳实践 。
这种模式可以防止控制器在没有依赖项的情况下被实例化(它会引发错误)。
如果您注入ServiceLocator
或ServiceManager
,您将从中解析类中的实际依赖项,那么不清楚该类实际需要什么。您最终可能会遇到一个缺少依赖项的类实例,这些依赖项本来就不应该创建。您需要在类中进行自定义检查以查看实际的依赖项是否可用,如果缺少则抛出错误。您可以使用构造函数依赖关系模式来阻止编写所有这些自定义代码。
另一个问题是,对您的课程进行单元测试比较困难,因为您无法轻松 为各个依赖项设置模拟 。
详细了解如何将依赖关系[{3}}注入类似问题。
关于您遇到的问题。控制器类实现ServiceLocatorAwareInterface
,并且在构造控制器类期间,ControllerManager
在类中注入ServiceLocator
。发生这种情况in my answer。就像@marcosh在他的回答中已经提到的那样,这可能是你注入的不同的服务定位器。在此injectServiceLocator
方法中,您还可以找到您在问题中提到的弃用声明。
您可以使用__construct
方法,因为那时(构建类之后)变量尚未被覆盖。稍后当您尝试使用getServiceLocator
方法访问它时,它会被覆盖。