PRE_WRITE 事件中的存储库 returns 查询数据,未保存数据

Repository in PRE_WRITE event returns query data, not saved data

在对项目进行 PUT 调用期间,我需要获取当前保存的值以便将它们与请求参数进行比较。

假设 PUT 调用包含一个 name 与当前保存的参数不同的参数。

我认为使用 $repository->findOneBy 获取实体会 return 保存的值,但事实并非如此,我正在获取 PUT 参数值。

设置取自https://api-platform.com/docs/core/events :

    const ALLOWED_METHOD = Request::METHOD_PUT;

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::VIEW => [
                ['preWriteWorkflow', EventPriorities::PRE_WRITE],

            ],
        ];
    }

    public function preWriteWorkflow(GetResponseForControllerResultEvent $event)
    {

        $entity = $event->getControllerResult();

        if (!($entity instanceof MyEntity)) {
            return;
        }
        
        $route = "/{$entity->getId()}";
        
        $result = $this->checkRequestFromControllerResult($event, $route);
        if (!$result) {
            return;
        }
        
        // Getting entity from repository in order to get the currently saved value
        $savedEntity = $this->MyEntityRepository->findOneBy(['id' => $entity->getId()]);
       
        // Both will return the Name value of the PUT call
        // Shouldn't $savedEntity return the currently saved name ?  
        $entity->getName();
        $savedEntity->getName();
    }

这种行为背后的原因是什么?有没有办法在这个方法中注入 eventArgs 以便我可以使用 getEntityChangeSethasChangedField?

What is the reason behind this behavior?

这是主义行为。获取实体后,实例将被存储并始终返回。鉴于此,在请求的生命周期中,您只有一个实体实例。

$event->getControllerResult() === $repository->findBy($id); //true !

粗略地说,Api-platform 在执行 ReadListener 时调用 Doctrine 并获取您的实体。因为这是一个对象,所以 doctrine 的 find*() 方法总是 returns a pointer/reference 到实体,即使它被更新了。 是的,在 PUT 请求期间,更新的实例是获取的实例,以便在请求结束时触发准则更新操作。

保留所谓的 previous object 实例的一种简单方法是 clone it before the Deserialization event.

请注意,此策略由 api-平台使用 security_post_denormalizeprevious_object security attributes

编辑

处理类似的用例,我发现 ReadListener 将当前对象存储在 Request 中的“数据”键下,而前一个对象存储在“ previous_data" 键。

$entity = $request->get('data');
$previousEntity = $request->get('previous_data'); // This is a clone.