我有一个案例,我想记录实体上发生的每一个变化。我使用了sonata-admin和doctrine管理包。我尝试了很多东西,但我想出了这个案例的最佳方法是什么。
第一次尝试是使用字段类型(创建/更新),更改(数组)以及相关实体类和ID创建ChangeLog实体。
我为postUpdate和postPersist事件设置了一个监听器:
appbundle.listen.ChangeLog:
class: AppBundle\Listener\ChangeLogListener
arguments: [@service_container]
tags:
- { name: doctrine.event_listener, event: postUpdate}
- { name: doctrine.event_listener, event: postPersist}
相关的听众:
public function prePersist(LifecycleEventArgs $args)
{
$this->buildLog($args, ChangeLog::TYPE_CREATE);
}
public function preUpdate(LifecycleEventArgs $args){
$this->buildLog($args, ChangeLog::TYPE_UPDATE);
}
private function buildLog(LifecycleEventArgs $args, $type)
{
$entity = $args->getEntity();
$clHelper = ChangeLogHelper::getInstance();
if ($entity instanceof ChangeLog) return;
$em = $args->getEntityManager();
$changes = $em->getUnitOfWork()->getEntityChangeSet($entity);
$user = $this->container->get('security.context')->getToken()->getUser();
$cl = new ChangeLog();
$cl->setUser($user);
$cl->setDate(new \DateTime());
$cl->setChangeset($changes);
$cl->setType($type);
$cl->setEntityName(get_class($entity));
$cl->setDescription('');
$cl->setEntityId($entity->getId());
$cl->setRefGroup($clHelper->getRefId());
$em->persist($cl);
$em->flush();
}
这适用于某些实体,但只要我有更多关系,我就会收到错误:
Catchable Fatal Error: Argument 3 passed to Doctrine\ORM\Event\PreUpdateEventArgs::__construct() ....
我发现无法解决这个问题,但我觉得它是因为监听器将被多次调用(对于实体本身和每个关系)而且最好在所有监听器的末尾刷新而不是每次调用它,但我没有看到任何方式使用post事件监听器设置。
经过几个小时的调试后,我认为如果我在ChangeLog实体上与其他实体之间存在多态关系可能会更好,我可以使用prePersist / preUpdate听众,所以我不必自己保留对象,并将其设置为已更改对象上的关系,并使用适当的级联。而且我试图避免在教义事件中使用entityManager。几个小时后,我仍然陷入困境,我无法找到一种与学说有这种关系的方法。基本上是一对多,有一个额外的列,其中定义了目标实体。
我试图让它与doctrine继承(STI和CTI)一起工作,但后来我的日志字段在实体本身上,而不再分离,我不想要。我试图在没有ChangeLog实体的拥有方的情况下解决这个问题,但是我无法在更改的实体上设置ChangeLog实体,因为它将被忽略。但我不知道如何定义拥有方面,基本上是对所有其他实体的引用,我现在不认为它可以用学说。
使用映射的超类和OneToMany关系,我将获得每个实体的连接表或连接列,这也是一种混乱。