2012-11-22 4 views
14

Ho l'entità Product con entità multi-to-one a Category. Ho bisogno di conservare Product in sessione. Prima di tutto cerco di implementare l'interfaccia \Serializable sul prodotto. Come dovrei serializzare la mia entità correlata Category? Devo implementare anche l'interfaccia \Serializable?Entità di esportazione Doctrine2 nell'array

ho letto, che la serializzazione nella dottrina è un'operazione molto dolore e penso a questo:

Possiamo ottenere valori grezzi da entità? Esattamente quei dati, che sono memorizzati nel database. Se riusciamo a ottenere questi valori, possiamo memorizzarli ovunque e ricreare l'oggetto!

Ho letto il codice doctrine2 e ho trovato il metodo Doctrine\ORM\Internal\Hydration\ObjectHydrator:hydrateRowData ma è protetto. C'è qualche apa pubblica per fare questo?

Aggiornamento:

Ho appena CopyPaste e integrare alcuni codice BasicEntityPersister e sembra funzionare.

$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 Abbiamo valori grezzi. Ora abbiamo bisogno modo come creare oggetti da questo array

risposta

7
<?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); 
    } 
} 
6

Ho avuto lo stesso problema, ho anche voluto avere i dati associati nella matrice troppo. Così mi è venuta con il seguente:

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

Fonte:

<?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; 
    } 
} 
+0

ringrazio molto per il vostro codice. Posso solo dire che avresti (appena prima della ricorsione) un test se '$ object' è nullo, perché potrebbero esserci relazioni non soddisfatte da nessuna istanza. –

+0

Questo ha funzionato per me, ma ho cambiato la riga "$ data [$ field] = $ this-> serialize ($ object);" a "$ data [$ field] = new \ Doctrine \ Common \ Collections \ ArrayCollection();" per evitare il problema "La classe 'Doctrine \ ORM \ PersistentCollection' non è stata trovata negli spazi dei nomi configurati a catena" – crafter