Symfony 将安全上下文注入(实体侦听器)类时的循环引用

Symfony 将安全上下文注入(实体侦听器)类时的循环引用,symfony,dependency-injection,Symfony,Dependency Injection,这里有两个问题说注入整个服务容器应该解决这个问题。但问题是。。。请参见下文(注意第2次尝试和第3次尝试之间的差异) 尝试1 public function __construct(SecurityContext $securityContext) { $this->securityContext = $securityContext); } 电流参考。好的 尝试2次 public function __construct(ContainerInterface $conta

这里有两个问题说注入整个服务容器应该解决这个问题。但问题是。。。请参见下文(注意第2次尝试和第3次尝试之间的差异)

尝试1

public function __construct(SecurityContext $securityContext) {
    $this->securityContext = $securityContext);  
}  
电流参考。好的

尝试2次

public function __construct(ContainerInterface $container) {
    $this->securityContext = $container->get('security.context');  
}  
循环引用(为什么?,我正在像try 3一样注入容器,除了我只获得了安全上下文)

尝试3次

public function __construct(ContainerInterface $container) {
    $this->container = $container;  
}  

工作。

发生这种情况是因为您的安全上下文依赖于此侦听器,可能是通过将实体管理器注入到用户提供程序中。最好的解决方案是将容器注入到侦听器中,并惰性地访问安全上下文

我通常不喜欢将整个容器注入到服务中,但对条令侦听器例外,因为它们被急切地加载,因此应该尽可能地懒惰。

原因“2”失败,“3”这不是因为在选项2中,您试图在容器可能尚未填充时立即从容器访问安全上下文

据我所知,Symfony2通过配置进行解析,一个接一个地实例化服务,然后继续处理请求的其余部分

这意味着您不必访问容器的各个部分,因为它可能以不同的顺序加载它们。因此,您拥有指向容器的内存指针,并将其存储,但在尝试访问部分容器之前,请让框架完成完整容器的构建。一个值得注意的例外是,当您直接将服务注入到另一个服务中时,容器会确保它首先加载了该服务


通过提供两个服务,您可以看到这一点的效果。A和B。A通过B,B通过A。现在你有了一个循环引用。如果您将容器同时传递到A和B,则无法从B和B从A访问A而不会出现问题。

自Symfony 2.6起,此问题应得到解决。一个拉入请求刚刚被接受到主机中。这里描述了您的问题。


从Symfony 2.6开始,您可以将
security.token\u存储
注入侦听器。此服务将包含中的
SecurityContext
所使用的令牌。您应始终避免将容器直接注入服务

我认为解决«循环参考»问题以及可能出现的性能问题的最佳方案是使用Symfony 2.3提供的«»功能

只需在服务容器配置中将依赖项标记为
lazy
,然后安装ProxyManager桥(在上面的lazy服务文档中查找详细信息)


我希望这有帮助,干杯。

请发布完整的代码示例。循环引用通常意味着您试图注入一个已经以其他方式注入到同一类中的服务。(最流行的问题是原则侦听器中的实体管理器)嗯,这是有道理的,但我不明白当3成功时,“Try 2”应该如何失败。是的,它是“懒惰的”,但是实例变量会扰乱另一个类的工作吗?嗯……容器跟踪它在创建过程中的服务。如果为其中一个已在创建过程中的服务调用了
get()
,则会引发循环引用异常。这就是为什么当您从构造函数内部调用安全上下文时会出现此异常,而不是从其他方面。调用构造函数时,容器已经在创建安全上下文。注入容器从来都不是“最佳解决方案”。我认为更好的方法是使用«Lazy Services»。尝试将对我的
EventSubscriber
的依赖项延迟加载,但这仍然导致相同的循环引用:现在是否有其他方法不将容器注入服务?这对我的情况有帮助。但有点奇怪的是,
ocramius/proxy manager
library(此功能需要能够使用)需要两个zendframework库。考虑到这些依赖关系,我怀疑对不太大的服务图使用延迟加载是否会带来速度优势。。
services:
    my.listener:
        class: EntityListener
        arguments:
            - "@security.token_storage"
        tags:
            - { name: doctrine.event_listener, event: prePersist }
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class EntityListener
{
    private $token_storage;

    public function __construct(TokenStorageInterface $token_storage)
    {
        $this->token_storage = $token_storage;
    }

    public function prePersist(LifeCycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entity->setCreatedBy($this->token_storage->getToken()->getUsername());
    }
}