[英]Injecting SecurityContext into a Listener prePersist or preUpdate in Symfony2 to get User in a createdBy or updatedBy Causes Circular Reference Error
我設置了一個偵聽器 class,我將在任何 doctrine prePersist 上設置 ownerid 列。 我的 services.yml 文件看起來像這樣......
services:
my.listener:
class: App\SharedBundle\Listener\EntityListener
arguments: ["@security.context"]
tags:
- { name: doctrine.event_listener, event: prePersist }
我的 class 看起來像這樣……
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\SecurityContextInterface;
class EntityListener
{
protected $securityContext;
public function __construct(SecurityContextInterface $securityContext)
{
$this->securityContext = $securityContext;
}
/**
*
* @param LifecycleEventArgs $args
*/
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entityManager = $args->getEntityManager();
$entity->setCreatedby();
}
}
這樣做的結果是以下錯誤。
ServiceCircularReferenceException:檢測到服務“doctrine.orm.default_entity_manager”的循環引用,路徑:“doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> my.listener -> security.context -> security.authentication.manager -> fos_user .user_manager”。
我的假設是安全上下文已經被注入到鏈中的某處,但我不知道如何訪問它。 有任何想法嗎?
我有類似的問題,唯一的解決方法是在構造函數中傳遞整個容器( arguments: ['@service_container']
)。
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
class MyListener
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
// ...
public function prePersist(LifeCycleEventArgs $args)
{
$securityContext = $this->container->get('security.context');
// ...
}
}
從Symfony 2.6開始,這個問題應該修復。 拉取請求剛剛被主人接受。 您的問題在此處描述。 https://github.com/symfony/symfony/pull/11690
從Symfony 2.6開始,您可以將security.token_storage
注入到監聽器中。 此服務將包含SecurityContext
在<= 2.5中使用的令牌。 在3.0中,此服務將完全替換SecurityContext::getToken()
。 您可以在此處查看基本更改列表: http : //symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service
2.6中的示例用法:
你的配置:
services:
my.entityListener:
class: App\SharedBundle\Listener\EntityListener
arguments:
- "@security.token_storage"
tags:
- { name: doctrine.event_listener, event: prePersist }
你的傾聽者
namespace App\SharedBundle\Listener;
use Doctrine\ORM\Event\LifecycleEventArgs;
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());
}
}
對於一個很好的created_by示例,您可以使用https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php獲取靈感。 它使用hostnet / entity-tracker-component,它提供在請求期間更改實體時觸發的特殊事件。 還有一個捆綁包可以在Symfony2中配置它
在這個帖子中已經有了一個很好的答案,但一切都在變化。 現在Doctrine中有實體監聽器類: http : //docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners-class
因此,您可以為實體添加注釋,如:
/**
* @ORM\EntityListeners({"App\Entity\Listener\PhotoListener"})
* @ORM\Entity(repositoryClass="App\Repository\PhotoRepository")
*/
class Photo
{
// Entity code here...
}
並創建一個這樣的類:
class PhotoListener
{
private $container;
function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/** @ORM\PreRemove() */
public function preRemoveHandler(Photo $photo, LifecycleEventArgs $event): void
{
// Some code here...
}
}
你也應該在services.yml
定義這個監聽器:
photo_listener:
class: App\Entity\Listener\PhotoListener
public: false
autowire: true
tags:
- {name: doctrine.orm.entity_listener}
我使用doctrine配置文件來設置preUpdate
或prePersist
方法:
Project\MainBundle\Entity\YourEntity:
type: entity
table: yourentities
repositoryClass: Project\MainBundle\Repository\YourEntitytRepository
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
lifecycleCallbacks:
prePersist: [methodNameHere]
preUpdate: [anotherMethodHere]
並且方法在實體中聲明,這樣您就不需要監聽器,並且如果您需要更通用的方法,您可以使BaseEntity保留該方法並從中擴展其他entite。 希望能幫助到你!
Symfony 6.2.4
將此添加到您的實體中:
#[ORM\EntityListeners(["App\Doctrine\MyListener"])]
將此添加到您的服務中。yaml:
App\Doctrine\MyListener:
tags: [doctrine.orm.entity_listener]
然后你可以這樣做:
<?php
namespace App\Doctrine;
use App\Entity\MyEntity;
use Symfony\Component\Security\Core\Security;
class MyListener
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function prePersist(MyEntity $myEntity)
{
//Your stuff
}
}
希望能幫助到你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.