Doctrine2 export entity to array

10,971

Solution 1

<?php

namespace Acme\ServiceBundle\Services;

use Doctrine\ORM\EntityManager;

class EntitySerializer
{
    protected $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function serialize($entity)
    {
        $className = get_class($entity);

        $uow = $this->em->getUnitOfWork();
        $entityPersister = $uow->getEntityPersister($className);
        $classMetadata = $entityPersister->getClassMetadata();

        $result = array();
        foreach ($uow->getOriginalEntityData($entity) as $field => $value) {
            if (isset($classMetadata->associationMappings[$field])) {
                $assoc = $classMetadata->associationMappings[$field];

                // Only owning side of x-1 associations can have a FK column.
                if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & \Doctrine\ORM\Mapping\ClassMetadata::TO_ONE)) {
                    continue;
                }

                if ($value !== null) {
                    $newValId = $uow->getEntityIdentifier($value);
                }

                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
                $owningTable = $entityPersister->getOwningTable($field);

                foreach ($assoc['joinColumns'] as $joinColumn) {
                    $sourceColumn = $joinColumn['name'];
                    $targetColumn = $joinColumn['referencedColumnName'];

                    if ($value === null) {
                        $result[$sourceColumn] = null;
                    } else if ($targetClass->containsForeignIdentifier) {
                        $result[$sourceColumn] = $newValId[$targetClass->getFieldForColumn($targetColumn)];
                    } else {
                        $result[$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
                    }
                }
            } elseif (isset($classMetadata->columnNames[$field])) {
                $columnName = $classMetadata->columnNames[$field];
                $result[$columnName] = $value;
            }
        }

        return array($className, $result);
    }

    public function deserialize(Array $data)
    {
        list($class, $result) = $data;

        $uow = $this->em->getUnitOfWork();
        return $uow->createEntity($class, $result);
    }
}

Solution 2

I've had the same problem, i also wanted to have to associated data in the array too. So i came up with the following:

$serializer = new Serializer($this->em); // Pass the EntityManager object
$array = $serializer->serialize($message); // Returns the array (with associations!)

Source:

<?php

/**
 * Class Serializer
 *
 * @author Steffen Brem
 */
class Serializer
{
    /**
     * @var Doctrine\ORM\EntityManager
     */
    private $_em;

    /**
     * Constructor
     *
     * @param \Doctrine\ORM\EntityManager $em
     */
    public function __construct(\Doctrine\ORM\EntityManager $em)
    {
        $this->_em = $em;
    }

    /**
     * Serialize entity to array
     *
     * @param $entityObject
     * @return array
     */
    public function serialize($entityObject)
    {
        $data = array();

        $className = get_class($entityObject);
        $metaData = $this->_em->getClassMetadata($className);

        foreach ($metaData->fieldMappings as $field => $mapping)
        {
            $method = "get" . ucfirst($field);
            $data[$field] = call_user_func(array($entityObject, $method));
        }

        foreach ($metaData->associationMappings as $field => $mapping)
        {
            // Sort of entity object
            $object = $metaData->reflFields[$field]->getValue($entityObject);

            $data[$field] = $this->serialize($object);
        }

        return $data;
    }
}
Share:
10,971

Related videos on Youtube

striker
Author by

striker

Updated on September 15, 2022

Comments

  • striker
    striker over 1 year

    I have Product entity with many-to-one to Category entity. I need store Product in session. First of all i try to implement \Serializable interface on Product. How should i serialize my related Category entity? Should i also implement \Serializable interface?

    I read, that serialization in doctrine is very pain operation and i think about this:

    Can we get raw values from entity? Exactly that data, which stored in database. If we can get this values, we can store it anywhere and recreate object!

    I read doctrine2 code and find method Doctrine\ORM\Internal\Hydration\ObjectHydrator:hydrateRowData but it's protected. Is there any public api for doing this?

    Update:

    I just copypaste and integrate some code from BasicEntityPersister and it seems to work.

        $product = $productsRepository->find($id);
    
        if (!$product) {
            throw $this->createNotFoundException('No product found for id ' . $id);
        }
    
        $uow = $em->getUnitOfWork();
        $entityPersister = $uow->getEntityPersister(get_class($product));
        $classMetadata = $entityPersister->getClassMetadata();
    
        $originalData = $uow->getOriginalEntityData($product);
    
        $result = array();
        foreach ($originalData as $field => $value) {
            if (isset($classMetadata->associationMappings[$field])) {
                $assoc = $classMetadata->associationMappings[$field];
    
                // Only owning side of x-1 associations can have a FK column.
                if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & \Doctrine\ORM\Mapping\ClassMetadata::TO_ONE)) {
                    continue;
                }
    
                if ($value !== null) {
                    $newValId = $uow->getEntityIdentifier($value);
                }
    
                $targetClass = $em->getClassMetadata($assoc['targetEntity']);
                $owningTable = $entityPersister->getOwningTable($field);
    
                foreach ($assoc['joinColumns'] as $joinColumn) {
                    $sourceColumn = $joinColumn['name'];
                    $targetColumn = $joinColumn['referencedColumnName'];
    
                    if ($value === null) {
                        $result[$owningTable][$sourceColumn] = null;
                    } else if ($targetClass->containsForeignIdentifier) {
                        $result[$owningTable][$sourceColumn] = $newValId[$targetClass->getFieldForColumn($targetColumn)];
                    } else {
                        $result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
                    }
                }
            } elseif (isset($classMetadata->columnNames[$field])) {
                $columnName = $classMetadata->columnNames[$field];
                $result[$entityPersister->getOwningTable($field)][$columnName] = $value;
            }
        }
    
        print_r($result);
    

    In $result we have raw values. Now we need way how to create object by this array

  • Nicolás Ozimica
    Nicolás Ozimica over 10 years
    Thank you very much for your code. I can only say that you would (just before the recursion) test if $object is null, because there may be relations not fulfilled by any instance.
  • crafter
    crafter about 9 years
    This worked for me, but I changed the line " $data[$field] = $this->serialize($object);" to "$data[$field] = new \Doctrine\Common\Collections\ArrayCollection();" to avoid the problem "The class 'Doctrine\ORM\PersistentCollection' was not found in the chain configured namespaces"