Symfony 5: "Maybe you forget to persist it in the entity manager?" --> Doctrine 贬值的 merge() 函数的替代方案

Symfony 5: "Maybe you forget to persist it in the entity manager?" --> Alternative for Doctrine's depreciated merge()-function

当我从会话中重新加载对象时,出现错误“您可能忘记将它保存在实体管理器中?”。

可以做什么?

有些情况下,您希望在会话中存储数据。一般来说,这在 Symfony 中运行良好。但是一旦你的数据包含 Doctrine-entities,你的代码迟早会爆炸。

Doctrine 正在提议 MERGE 函数(参见:https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/cookbook/entities-in-session.html),但此函数已标记为已弃用。

在这里,您会发现一个函数,一旦从会话中加载回来,就可以使 doctrine-data 恢复活力,从而使您的代码工作得非常好。

用法

public function anyName() {
  // ...
  $data = $this->session->get('myData', $default_data);
  $data = $this->sessionHelper->revitalizeEntityObjects($data);
  // ...
}

替代 MERGE

<?php


namespace App\Service;


use Doctrine\ORM\EntityManagerInterface;
use ReflectionClass;

class SessionHelper
{
    const DB_NAMESPACE_NAME = "App\Entity";

    private $emi;

    public function __construct(EntityManagerInterface $emi) {
        $this->emi = $emi;
    }

    public function revitalizeEntityObjects(object $object)
    {
        $reflect = new ReflectionClass($object);
        $props   = $reflect->getProperties();

        foreach ($props as $prop) {
            $propName = $prop->getName();
            $propName = ucfirst($propName); // capitalize first letter
            $getter   = "get{$propName}";   // name of the getter-function
            $setter   = "set{$propName}";   // name of the setter-function

            // check if the property has a GETTER and SETTER (else go to next property)
            if ( ! $reflect->hasMethod($getter) ) { continue; }
            if ( ! $reflect->hasMethod($setter) ) { continue; }

            // get the value of the property
            $value = $object->$getter();

            // check if the value is an object (else go to next property)
            if ( ! is_object($value)) { continue; }

            // check if the object has the expected namespace-prefix (else go to next property)
            $subReflect = new ReflectionClass($value);
            if ($subReflect->getNamespaceName() !== self::DB_NAMESPACE_NAME) { continue; }

            // check if the ID-Field can be fetched by the standard 'getId'-function
            if ( ! $subReflect->hasMethod('getId') ) { continue; }

            // get the classname of the entity and the repository of that entity
            $classname  = $subReflect->getName();
            $repository = $this->emi->getRepository($classname);

            // re-fetch the object from the database
            $reloadedObject = $repository->find($value->getId());

            // check if something has been fetched (else do nothing and go to next property)
            if ( ! $reloadedObject) { continue; }

            // store the re-fetched object back into the main-object
            $object->$setter($reloadedObject);

        }

        return $object;
    }
}

蒂姆