Doctrine 3 слияния альтернативных - PullRequest
0 голосов
/ 27 февраля 2020

В настоящее время я использую doctrine слияния, чтобы "восстановить" сущность со связями после извлечения ее из сеанса.

Начиная с doctrine 3, эта функция устарела, поэтому мне интересно, есть ли любой способ сохранить объект сущности в сеансе некоторое время, прежде чем сохранить его в базе данных.

Мне нужно это для многошаговой формы, через которую заполняется мой объект.

Пока единственное решение, которое я вижу, - это сохранение сущности во временной таблице базы данных, но мне не очень нравится эта идея, потому что моя таблица будет заполнена "мусором".

Спасибо !

1 Ответ

1 голос
/ 27 февраля 2020

Я нашел два способа.

Первый - создать собственную реализацию. У меня go таким образом, потому что в проекте было много случаев использования merge. Выглядит хакерски, но работает:

class DoctrineMergeService
{
    /**
     * @var EntityManager
     */
    private $em;

    /**
     * @param EntityManager $em
     */
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    /**
     * @param object $entity
     *
     * @return object
     *
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     * @throws \Doctrine\ORM\TransactionRequiredException
     */
    public function merge(object $entity): object
    {
        $mergedEntity = null;
        $className = get_class($entity);
        $identifiers = $this->getIdentifiersFromEntity($entity);
        $entityFromDoctrine = $this->em->find($className, $identifiers);

        if ($entityFromDoctrine) {
            $mergedEntity = $this->mergeEntities($entityFromDoctrine, $entity);
        } else {
            $this->em->persist($entity);
            $mergedEntity = $entity;
        }

        return $mergedEntity;
    }

    /**
     * @param object $entity
     *
     * @return array
     */
    private function getIdentifiersFromEntity(object $entity): array
    {
        $className = get_class($entity);
        $meta = $this->em->getClassMetadata($className);
        $identifiers = $meta->getIdentifierValues($entity);

        return $identifiers;
    }

    /**
     * @param object $first
     * @param object $second
     *
     * @return object
     */
    private function mergeEntities(object $first, object $second): object
    {
        $classNameFirst = get_class($first);
        $metaFirst = $this->em->getClassMetadata($classNameFirst);
        $classNameSecond = get_class($second);
        $metaSecond = $this->em->getClassMetadata($classNameSecond);

        $fieldNames = $metaFirst->getFieldNames();
        foreach ($fieldNames as $fieldName) {
            $secondValue = $metaSecond->getFieldValue($second, $fieldName);
            $metaFirst->setFieldValue($first, $fieldName, $secondValue);
        }

        return $first;
    }
}

Второй - использовать сериализатор , не тестировался:

// this is controller or something like controller
public function save($id)
{
    $serializedJsonFromSession = $this->session->get('serialized_json');

    $doctrine = $this->getDoctrine();
    $entity = $doctrine->getRepository(Entity::class)->find($id);
    if (!$entity) {
        $entity = new Entity();
        $doctrine->persist($entity);
    }

    $serializer->deserialize(
        $serializedJsonFromSession, 
        Entity::class, 
        'json', 
        [AbstractNormalizer::OBJECT_TO_POPULATE => $entity]
    );

    $doctrine->flush();
}
...