Symfony 4 - 尽管它是公共的,但服务已被删除或内联化

26
我正在尝试将一个带有新目录结构的SF 4应用从SF 3.3迁移到SF 4。

我遇到了这个异常:

在容器编译时,“simplethings_entityaudit.reader”服务或别名已被删除或内联。您应该将其公开,或停止直接使用容器并改为使用依赖注入。

(此服务来自位于/vendor的外部bundle)。

然而,当我运行bin/console debug: container simplethings_entityaudit.reader时,您会看到该服务存在且为public:

Information for Service "simplethings_entityaudit.reader"
=========================================================
----------------- -------------------------------------- Option Value ----------------- -------------------------------------- Service ID simplethings_entityaudit.reader Class SimpleThings\EntityAudit\AuditReader Tags - Public yes Synthetic no Lazy no Shared yes Abstract no Autowired no Autoconfigured no Factory Service simplethings_entityaudit.manager Factory Method createAuditReader ----------------- --------------------------------------

目前我的服务中使用以下方法调用此服务:$this->container->get('simplethings_entityaudit.reader')

我还尝试将SimpleThings\EntityAudit\AuditReader注入到我的服务构造函数中,但是我得到了以下错误:

方法“__construct()”的参数“$auditReader”引用类“SimpleThings\EntityAudit\AuditReader”,但不存在这样的服务。它无法自动注册,因为它来自不同的根命名空间。

当我将其添加到我的services.yaml时,它可以正常工作,但我应该不需要这样做:

SimpleThings\EntityAudit\AuditReader:
    alias: simplethings_entityaudit.reader

有什么想法吗?


别名没问题,但如果外部bundle没有提供Symfony 4兼容的别名,你可以怎么做呢?如果这是你的bundle,请在其中添加别名。 - malcolm
由于答案中并不清楚,因此请添加属性 public:true 作为别名的同级。 - john Smith
5个回答

22

在我的情况下,出现了一个单元测试错误。

我有一个单一的服务,在测试中无法加载(Symfony 4.2),而我项目中的所有其他服务都能正常工作。

我清除了缓存,但没有帮助。然后我创建了一个简单的控制器和路由,并将服务注入为方法参数。之后,该服务也可以在我的测试中工作。

结论:如果您有一个单元测试并想测试您的服务,则必须提供一个控制器,其中包含注入服务,否则该服务不会出现在测试服务容器中。显式的服务配置也可能有所帮助。


7
这至少部分是不正确的。加入控制器可能只是将服务标记为已使用,因此在容器转储期间不会对其进行修剪。 - Alessandro Lai
1
确实,服务必须首先在某个地方使用:在控制器中,在命令中...从另一个服务等等... - myselfhimself
事实上,更直接和明确的解决方法是在services.yml中添加public:true,将您的服务公开化。 - Vincent
这对我来说根本不起作用 - naspy971

9
在我们的情况下,我们制作了一个包含services_test.yml.env.test的文件,并将APP_ENV设置为test
然后,在这个services_test.yml文件中,我们放置了:
services:
    _defaults:
        public: true

默认情况下,所有服务都是公开的。

别忘了引用你的.env.env.test。我经常在重新启动我的虚拟机时这样做。


9
在Symfony 4.0中,任何未指定其可见性的服务都是私有的,详情请查看https://github.com/symfony/symfony/pull/24238
就我所知,您提到的服务没有指定可见性:https://github.com/simplethings/EntityAuditBundle/blob/1.0/src/SimpleThings/EntityAudit/Resources/config/auditable.xml#L23-L26,这可能是您遇到异常的原因。
如果simplethings_entityaudit.reader服务无法进行自动装配(这可能是因为它使用了工厂服务),您可以通过使用@simplethings_entityaudit.reader注释引用它,并将其注入到您自己的服务中,如下所示:https://symfony.com/doc/current/service_container.html#services-manually-wire-args
services:
    My\Service:
        arguments:
            $auditReader: @simplethings_entityaudit.reader

你好 Edi,我知道确实如此,但由于某种原因,在执行debug:container时将该服务标记为public。当你说“这可能是因为它使用了一个工厂服务”时,这种行为在哪里记录?我从来没有听说过。谢谢,Ben - Ben
哦,我以为debug:container命令的输出来自Symfony 3.3。在Symfony 4.0上,我不确定为什么它应该显示为公共输出。至于自动装配和工厂服务,我不知道是否有任何文档记录,这只是一个猜测,因为它似乎是一个合理的原因,为什么不能自动装配,因为自动装配系统不知道如何构建服务。另一个潜在的原因可能是对于该服务,自动装配根本没有开启(因为它没有在其配置文件中进行配置),但这些只是猜测。 - Edi Modrić
2
实际上这是一个在最新的Symfony 4.0.x版本中修复的错误。 - Ben
4
好的,根据你所建议和发布的文档,其中一个选项是使用 public: true 来设置服务的可见性。 - FantomX1
我只是添加了这个文档,因为它在这种情况下很有帮助:https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private - vincent PHILIPPE

5

我在我的单元测试KernelTestCase中遇到了同样的问题。

当您尝试使用容器加载一个在应用程序中没有任何引用的服务时,问题就会出现。 要解决这个问题,只需将该服务包含在您的控制器或另一个始终在应用程序中注册的服务中,或手动在services.yaml中注册它即可。

// Doesnt work in test case when not registered somewhere else
static::getContainer()->get(MyService::class);

但是如果我们在某个地方引用它,那么我们就可以在测试中使用 container 来获取它:

class MyController {

  public function __construct(protected MyService $myService) {}

}


class AnotherTestCase extends KernelTestCase {

  public function setUp() {
    // Now works because service is used in controller and therefore present in compiled container.
    $myService = static::getContainer()->get(MyService::class);
  }
}


1
我遇到了同样的问题,依赖注入和添加服务都没有起作用。后来我发现别名是在PHP代码中设置的,然后在那里添加->setPublic(true)就解决了我的问题。
帮助过我的参考链接: https://symfony.com/doc/current/service_container/alias_private.html
use Symfony\Component\DependencyInjection\ContainerBuilder;

//...
public function load(ContainerBuilder $container)
{
    $container->setAlias('simplethings_entityaudit.reader', 'SimpleThings\EntityAudit\AuditReader')
              ->setPublic(true);
}
//...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接