Как обновить сущность Doctrine из сериализованного JSON? - PullRequest
8 голосов
/ 04 января 2012

Мы используем Symfony2 для создания API.При обновлении записи мы ожидаем, что вход JSON будет представлять сериализованную обновленную сущность.Данные JSON не будут содержать некоторые поля (например, CreatedAt должен быть установлен только один раз при создании объекта - и никогда не обновляться).Например, вот пример запроса JSON PUT:

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

Вот код PHP на контроллере, который должен обновить объект в соответствии с JSON выше (мы используем комплект JMS-сериализатора):

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

EntityManger понимает (правильно), что это запрос на обновление (фактически запрос SELECT запускается неявно).EntityManager также предполагает (не правильно), что свойство CreatedAt должно иметь значение NULLified - вместо этого оно должно сохранять предыдущее.

Как решить эту проблему?

Ответы [ 3 ]

14 голосов
/ 14 мая 2013

с использованием JMSSerializerBundle следуйте инструкциям по установке в http://jmsyst.com/bundles/JMSSerializerBundle

, либо создайте собственную службу сериализатора, либо измените JMSSerializerBundle, чтобы использовать конструктор объекта doctrine вместо простого конструктора объекта.1006 * Это в основном обрабатывает именно то, что делает решение Ocramius, но с использованием десериализации JMSSerializerBundles.

9 голосов
/ 30 января 2012

Я бы использовал Doctrine\ORM\Mapping\ClassMetadata API для обнаружения существующих полей в вашей сущности. Вы можете сделать следующее (я не знаю, как работает JMSSerializerBundle):

//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();
4 голосов
/ 13 декабря 2018

Также возможно сделать это с Symfony Serializer с использованием опции object_to_populate .

Пример: Я получаю запрос JSON.Если запись существует в базе данных, я хочу обновить поля, полученные в теле, если она не существует, я хочу создать новую.

/**
 * @Route("/{id}", methods={"PUT"})
 */
public function upsert(string $id, Request $request, SerializerInterface $serializer)
{
  $content = $request->getContent(); // Get json from request

  $product = $this->getDoctrine()->getRepository(Product::class)->findOne($id); // Try to find product in database with provided id

  if (!$product) { // If product does not exist, create fresh entity
      $product = new Product();
  }

  $product = $serializer->deserialize(
            $content,
            Product::class,
            'json',
            ['object_to_populate' => $product] // Populate deserialized JSON content into existing/new entity
        );
  // validation, etc...
  $this->getDoctrine()->getManager()->persist($product); // Will produce update/instert statement 
  $this->getDoctrine()->getManager()->flush($product);

// (...)
...