【问题标题】:Deprecated: Retrieve service locator in functional system - ZF2已弃用:在功能系统中检索服务定位器 - ZF2
【发布时间】:2016-07-03 20:09:39
【问题描述】:

我正在开发一个 ZF2 系统,它运行良好,但是在我将存储库克隆到其他计算机后,出现了这个已弃用的错误:

您正在从类 Module\Controller\Controller 中检索服务定位器。请注意,ServiceLocatorAwareInterface 已弃用,将在 3.0 版中与 ServiceLocatorAwareInitializer 一起删除。您将需要更新您的类以在创建时接受所有依赖项,通过构造函数参数或设置器,并使用工厂执行注入。在 /home/path/project/vendor/zendframework/zend-mvc/src/Controller/AbstractController.php 第 258 行

composer.json:

"require": {
    "php": ">=5.5",
    "ext-curl": "*",
    "ext-json": "*",
    "ext-mbstring": "*",
    "zendframework/zendframework": "~2.5",
    "doctrine/doctrine-orm-module": "0.*",
    "hounddog/doctrine-data-fixture-module": "0.0.*",
    "imagine/Imagine": "~0.5.0"

当我在控制器中检索服务时出现错误(扩展 Zend\Mvc\Controller\AbstractActionController):

$this->getServiceLocator()->get("Module\Service\Service");

在 Zend\Mvc\Controller\AbstractController 的 Zend 核心中是这样的:

public function getServiceLocator()
{
    trigger_error(sprintf(
        'You are retrieving the service locator from within the class %s. Please be aware that '
        . 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along '
        . 'with the ServiceLocatorAwareInitializer. You will need to update your class to accept '
        . 'all dependencies at creation, either via constructor arguments or setters, and use '
        . 'a factory to perform the injections.',
        get_class($this)
    ), E_USER_DEPRECATED);

    return $this->serviceLocator;
}

以前只有这个:

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

我什么都试过了,有人知道我该怎么做吗?

【问题讨论】:

标签: php zend-framework zend-framework2 deprecated zend-framework3


【解决方案1】:

你不必做任何事情,。当您升级到 ZF3 时,您将不得不更改 控制器类 接收其依赖项的方式。

ZF2 支持两种依赖注入模式:通过服务定位器和通过构造器。 ZF3 删除了“按服务位置”并要求“按构造函数”。所有这一切实际上都是改变依赖关系的解决方式,将解决方案从“及时”转变为“构建时”。

您无法从任何地方获得服务,而是在建筑处获得服务。按照以下几行更新您的代码:

namespace Module\Controller;

class Controller {
    public function __construct(\Module\Service\Service $service) {
        $this->service = $service;
    }
}

在类方法中需要它的地方使用$this->service

然后使用控制器工厂来创建您的控制器,如下所示:

function ($controllers) { 
    $services = $controllers->getServiceLocator();
    return new \Module\Controller\Controller($services->get('Module\Service\Service')); 
} 

Issue 5168 中讨论了更改,this blog post 讨论了为什么使用服务定位器进行服务注入是一种反模式。

【讨论】:

  • 您能否为不同操作需要不同服务的控制器推荐一种解决方案?例如,我的 indexAction 需要用户服务,viewAction 需要用户服务和产品服务,而我的 aboutUsAction 可能根本不需要服务。我的观点是,对于这样的控制器,在构造函数中为每个请求实例化和传递所有服务是没有意义的。
  • @helloworld 你说得对,注入所有这些服务是没有意义的,我认为这正是这一变化的重点:迫使开发人员考虑适用于控制器的单一职责原则.对我来说,听起来你有一个“胖”控制器,解决方案是为这些操作创建单独的控制器。如果您将具体示例发布到 [codereview SE](codereview.stackexchange.com),您可以获得更具体的反馈。
  • 感谢您的反馈。我将努力使控制器遵守 SRP。
【解决方案2】:

你可以创建一个控制器插件service()(但这是一个不好的做法,更喜欢FactoryInterface)

module.config.php

'controller_plugins' => [
    'factories' => [
        'service' => YourNamespace\Mvc\Controller\Plugin\Service\ServiceFactory::class,
    ],
],

YourNamespace\Mvc\Controller\Plugin\Service\ServiceFactory.php

<?php

namespace YourNamespace\Mvc\Controller\Plugin\Service;

use Interop\Container\ContainerInterface;
use YourNamespace\Mvc\Controller\Plugin\Service;
use Zend\ServiceManager\Factory\FactoryInterface;

class ServiceFactory implements FactoryInterface
{
    /**
     * @param  ContainerInterface $container
     * @param  string $requestedName
     * @param  array $options
     * @return Service
     */
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $plugin = new Service();
        $plugin->setServiceLocator($container);
        return $plugin;
    }
}

YourNamespace\Mvc\Controller\Plugin\Service.php

<?php

namespace YourNamespace\Mvc\Controller\Plugin;

use Interop\Container\ContainerInterface;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;

/**
 * Plugin: $this->service();
 */
class Service extends AbstractPlugin
{
    /**
     * @var ContainerInterface
     */
    protected $serviceLocator;

    /**
     * @return ContainerInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }

    /**
     * @param  ContainerInterface $serviceLocator
     * @return Service
     */
    public function setServiceLocator(ContainerInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }

    /**
     * @param  string $name
     * @return object|bool
     */
    public function __invoke($name = null)
    {
        $sl = $this->getServiceLocator();
        if (!$name) {
            return $sl;
        }
        if (!$sl->has($name)) {
            return false;
        }
        return $sl->get($name);
    }
}

【讨论】:

  • FactoryInterface 会怎么样?
  • 喜欢ServiceFactory,但使用$controller = new YourController(); $controller-&gt;setService($container);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 2016-11-25
  • 2021-11-18
相关资源
最近更新 更多