2012-01-04 23 views
8

Chúng tôi đang sử dụng Symfony2 để tạo API. Khi cập nhật một bản ghi, chúng tôi mong đợi đầu vào JSON đại diện cho một thực thể được cập nhật theo thứ tự. Dữ liệu JSON sẽ không chứa một số trường (ví dụ, CreatedAt chỉ nên được thiết lập một lần khi thực thể được tạo ra - và không bao giờ được cập nhật). Ví dụ, đây là một yêu cầu ví dụ JSON PUT:Làm thế nào để cập nhật một thực thể Doctrine từ một JSON được tuần tự hóa?

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

Đây là mã PHP trên Controller mà nên cập nhật các đối tượng theo quy định của JSON trên (chúng tôi đang sử dụng JMS serializer Bundle):

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

EntityManger hiểu (chính xác) rằng đây là một yêu cầu cập nhật (trên thực tế, một truy vấn SELECT được ngầm kích hoạt). EntityManager cũng đoán (không chính xác) thuộc tính CreatedAt nên được NULL hóa - thay vào đó hãy giữ thuộc tính trước đó.

Cách khắc phục vấn đề này?

Trả lời

8

Tôi sẽ sử dụng API Doctrine\ORM\Mapping\ClassMetadata để khám phá các trường hiện có trong thực thể của bạn. Bạn có thể làm như sau (tôi không biết làm thế nào JMSSerializerBundle hoạt động):

//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

sử dụng JMSSerializerBundle làm theo hướng dẫn cài đặt tại http://jmsyst.com/bundles/JMSSerializerBundle

thể tạo dịch vụ serializer của riêng bạn hoặc thay đổi JMSSerializerBundle sử dụng doctrine object constructor thay vì constructor đối tượng đơn giản.

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

Điều này về cơ bản xử lý chính xác giải pháp Ocramius nào nhưng sử dụng JMSSerializerBundles deserialize.

Các vấn đề liên quan