在插件管理器 Zend\Mvc\Controller\PluginManager 中找不到名为 "getServiceLocator" 的插件

A plugin by the name "getServiceLocator" was not found in the plugin manager Zend\Mvc\Controller\PluginManager

最近开始通过课程学习 AngularJS 和 Zend Framework 2。考虑到课程的年份,如果我记得是 2013 年,两个框架中的一些事情都发生了变化。很快,我遇到了使用以下代码片段测试与数据库的连接并使用 Doctrine 2 列出记录的问题:

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController {
    public function indexAction() {
        $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        $repo = $em->getRepository('Entity\Categoria');

        $categorias = $repo->findAll();

        return new ViewModel(['categories'=>$categorias]);
    }
}

当我运行时,它returns出现以下错误::

A plugin by the name "getServiceLocator" was not found in the plugin manager Zend\Mvc\Controller\PluginManager

此外,补充一个信息:

Zend\ServiceManager\Exception\ServiceNotFoundException

文件:

C:\xampp\htdocs\Curso de ZF2\vendor\zendframework\zend-servicemanager\src\AbstractPluginManager.php:133

据我所知,问题源于 getServiceLocator() 已从最新版本的 Zend Framework 2 中删除。但是,我不知道如何解决这个问题,以便我可以继续测试。有人可以帮助我吗?

如果您已经从 composer 更新或签出 Zend Framework 3,并且如果它只是为了让您的课程 material 正常工作,您可以降级到更早的 (2.x) 版本,其中 getServiceLocator() 可用,但 已弃用 。它从 3.0 开始被删除。

更好的方法是了解如何解决它,因为无论如何您将来都必须这样做。基本上,您不应该在运行时注入依赖项,而是实际上为您的控制器注册一个工厂,然后通过构造函数传递依赖项。可能的修复在以下问题的接受答案中得到了很好的解释:

在上面的示例中,$db = $this->getServiceLocator()->get('Db\ApplicationAdapter'); 作为构造函数参数传递,因此它将立即可供控制器使用。所以以类似的方式,你应该为你的 IndexController 创建一个工厂,它应该 return 它已经通过构造函数注入 Doctrine\ORM\EntityManager (记得用你的真实替换 "yourModule"模块名称):

namespace yourModule\Controller\Factory;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use yourModule\Controller\IndexController;

class IndexControllerFactory implements FactoryInterface {
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null) {
        return new IndexController($container->get('Doctrine\ORM\EntityManager'));
    }
}

您可以将您的工厂 class 放置在任何地方,只要一切都进行了相应的配置。在这个例子中,我把它放在 /Module/yourModule/src/yourModule/Controller/Factory/IndexControllerFactory.php.

随着上面的 class 被调用,您的 $em 变量将被填充并且可以从控制器中的任何地方调用(注意新的 属性 $em及其用法:$this->em):

class IndexController extends AbstractActionController {

    protected $em;

    public function __construct(EntityManager $em) {
        $this->em = $em;
    }

    public function indexAction() {
        $repo = $this->em->getRepository('Entity\Categoria');
        $categorias = $repo->findAll();
        return new ViewModel(['categories'=>$categorias]);
    }

    ...

}

现在,在您的模块 module.config.php 中注册您的新工厂,我们就完成了:

<?php
return [
    // ... other stuff
    // ...
    'controllers' => [
        'factories' => [  
            'yourModule\Controller\Index' => 'yourModule\Controller\Factory\IndexControllerFactory',
            ],
    ],
    // etc...
]; 
// end of file

非常重要: 您的文件可能有相似的内容,但使用 "invokes" 作为数组键。请注意,您将使用 factories 作为键名(因为您正在声明一个控制器工厂),而不是 "invokes",后者适用于 class 没有依赖项或常规控制器。

我也建议学习这个Migration guide for Zend Framework 3,它有很多重要的信息可能会有所帮助。

至于您正在学习的那门课程,我再次建议您将 PHP 降级到兼容版本(如果您使用的是 composer,这很容易),或者尝试找到另一门最新的课程或网络教程。 ZF2 在版本之间发生了显着变化,这可能不是您会发现的唯一错误,您会感到非常困惑而不是学习。让我知道这是否适合你。