2012-01-04 4 views
8

Używamy Symfony2 do tworzenia interfejsu API. Aktualizując rekord, spodziewamy się, że dane wejściowe JSON będą reprezentować zaktualizowaną serializowaną encję. Dane JSON nie będą zawierać niektórych pól (na przykład CreateAt powinno być ustawione tylko raz, gdy jednostka jest tworzona - i nigdy nie jest aktualizowana). Na przykład, tutaj jest prośba przykład JSON PUT:Jak zaktualizować encję Doktryny z serializowanego JSON?

{"id":"1","name":"anyname","description":"anydescription"} 

Oto kod PHP na kontrolerze, który powinien zaktualizować podmiot zgodnie z JSON powyżej (używamy JMS serializer Bundle):

$supplier = $serializer->deserialize(
    $this->get('request')->getContent(), 
    'WhateverEntity', 
    'json' 
); 

EntityManger rozumie (poprawnie), że jest to żądanie aktualizacji (w rzeczywistości zapytanie SELECT jest niejawnie wyzwalane). EntityManager również domyśla się (niepoprawnie), że właściwość CreatedAt powinna mieć wartość NULL - zamiast tego powinna ona zachować poprzednią.

Jak naprawić ten problem?

Odpowiedz

8

Chciałbym użyć interfejsu API Doctrine\ORM\Mapping\ClassMetadata, aby odkryć istniejące pola w twojej encji. Można to zrobić następująco (nie wiem jak JMSSerializerBundle działa):

//Unserialize data into $data 
$metadata = $em->getMetadataFactory()->getMetadataFor($FQCN); 
$id = array(); 
foreach ($metadata->getIdentifierFieldNames() as $identifier) { 
    if (!isset($data[$identifier])) { 
     throw new InvalidArgumentException('Missing identifier'); 
    } 
    $id[$identifier] = $data[$identifier]; 
    unset($data[$identifier]); 
} 
$entity = $em->find($metadata->getName(), $id); 
foreach ($metadata->getFieldNames() as $field) { 
    //add necessary checks about field read/write operation feasibility here 
    if (isset($data[$field])) { 
     //careful! setters are not being called! Inflection is up to you if you need it! 
     $metadata->setFieldValue($entity, $field, $data[$field]); 
    } 
} 
$em->flush(); 
14

pomocą JMSSerializerBundle postępuj zgodnie z instrukcjami instalacji w http://jmsyst.com/bundles/JMSSerializerBundle

albo stworzyć swój własny serwis serializer lub zmienić JMSSerializerBundle używać konstruktor obiektów doktryny zamiast prostego konstruktora obiektów.

<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/> 

Zasadniczo zajmuje dokładnie to, co robi, ale rozwiązanie Ocramius Używanie JMSSerializerBundles deserializowania.