【问题标题】:Doctrine preUpdate event shows no changeset for associated collectionsDoctrine preUpdate 事件未显示关联集合的变更集
【发布时间】:2022-01-02 13:29:48
【问题描述】:

这是关于 Doctrine 中事件系统的问题(在 Symfony 项目中)。

我有两个类,用户和访问,它们通过多对多关系关联。 IE。一个用户可以有很多次访问,一次访问可以有很多用户(参加访问)。

class Visit 
{
    #[ORM\Column]
    protected string $Date;
    
    #[ORM\ManyToMany(targetEntity: User::class, inversedBy: "Visits")]
    #[ORM\JoinTable(name: "users_visits")]
    protected Collection $Users;

    public function __construct()
    {        
        $this->Users = new ArrayCollection();
    }

    //... other properties and methods omitted
}

class User
{
    #[ORM\Column]
    protected string $Name;
    
    #[ORM\ManyToMany(targetEntity: Visit::class, inversedBy: "Users")]
    #[ORM\JoinTable(name: "users_visits")]
    protected Collection $Visits;

    public function __construct()
    {        
        $this->Visits = new ArrayCollection();
    }

    //... other properties and methods omitted
}

我还有一个 UpdateSubscriber,它应该在单独的 sql 表中记录某些插入、更新或删除,以便稍后创建所有相关更改的概览。

class UpdateSubscriber implements EventSubscriberInterface
{
    public function __construct(private LoggerInterface $logger)
    {
    }

    public function getSubscribedEvents(): array
    {
        return [
            Events::preUpdate,
            Events::postPersist,
            Events::postRemove,
            Events::postFlush
        ];
    }

    public function preUpdate(PreUpdateEventArgs $args): void
    {
        $this->logger->debug('Something has been updated');
        if($args->hasChangedField('Date')){
            $this->logger->debug('The date has been changed.');
        }
        if($args->hasChangedField('Users')){
            $this->logger->debug('It was the Users field');
        }
    }

    // ... other methods emitted

我已经让这个系统工作了,但是当我运行这个测试代码时

    $visitRepo = $this->om->getRepository(Visit::class);
    $userRepo = $this->om->getRepository(User::class);
    // you can assume that visit 7 and user 8 already exist in the database
    $v = $visitRepo->find(7);
    $u = $userRepo->find(8);

    $v->setDate('2022-01-05');
    $this->om->flush();
                
    $v->addUser($u);
    $this->om->flush();                

测试代码正常工作,我可以在 sql 表“users_visits”中看到一个新行。我还可以看到访问 7 的日期已更改为 2022-01-05。

但是:查看日志我只能找到

Something has been updated.
The date has been changed.
Something has been updated.

没有“这是用户字段”。使用我的调试工具,我可以看到 EntityChangeSet 在 $v->addUser($u) 期间的 preUpdate() 期间为空,这很奇怪且出乎意料。

我已经广泛阅读了docs for the event PreUpdate,但没有提及为什么对关联集合的更改未显示在 EntityChangeSet 中,或者我如何在 EventSubscriber 中跟踪这些更改。

在 onFlushEvent 期间我是否必须通过相当繁琐的 UnitOfWork?或者这是我错过了什么?

【问题讨论】:

    标签: php symfony doctrine-orm doctrine


    【解决方案1】:

    如果我自己或其他人读到这篇文章,我非常肮脏的解决方案是收集所有当前更新的集合,然后检查属性(在这种情况下为“用户”)是否匹配这些。

    $updatedCollectionNames = array_map(
        function (PersistentCollection $update) {
            return $update->getMapping()['fieldName'];
        },
        $args->getEntityManager()->getUnitOfWork()->getScheduledCollectionUpdates()
    );
    
    // and later
    if (in_array('Users', $updatedCollectionNames, true)){
        $this->logger->debug('It was the Users field');
    }
    

    这看起来很肮脏和做作,但在有人提出更好的建议之前,它现在可以。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 2011-12-31
      相关资源
      最近更新 更多