0

I'm implementing a REST Api with FOSRestBundle and I have encountered a problem with the modification of existing entity (PUT)

I have a class Student with has a ManyToOne relation

/**
 * @JMS\MaxDepth(2)
 * @ORM\ManyToOne(targetEntity="ClassRoom", inversedBy="students")
 * @ORM\JoinColumn(name="classroom_id", referencedColumnName="id")
 */
protected $classRoom;

When performing a PUT action I only receive the value attributes since i do not want to let the user modify the relations via a put request. This is a received data example.

{
"id": 3,
"name": "pelayo",
"second_name": "ramon",
"last_name": "fernandez",
"birthday": "1983-08-15T00:00:00+0200"
}

Data gets deserialized with JMS serializer wich sets the $classRoom attribute to null since it didn't find it in the received data.

When performing a merge

$student2 = $this->get('doctrine')->getManager()->merge($student);

If the student2 gets persisted the current relation with classRoom gets erased from the database since the merge sets the relation to null.

This behavior can be dodged by retrieving the current classRoom and setting it to the deserialized entity by hand before the merge, but this is ugly.

Is there any way to tell doctrine to ignore an attribute in a merge from the detached one and make it always use the stored value?

Nodens
  • 354
  • 1
  • 3
  • 11
  • Stumbled upon this too, entity manager merge means merge-detached-entitites-to-em, not merge-that-data-to-entity. Your deserialized entity was not previously detached so is not in proper state to be merged as I understand it. You probably shoud merge updated data to newly fetched entity - this will even prepare you for implementing partial update (PATCH method) – jkavalik Mar 14 '14 at 09:33
  • The problem with merging the data to a fetched entity is that it is a tedious and prone to error method. Maybe I should develop a annotation and a service that reads its value to know witch attributes to "merge". – Nodens Mar 14 '14 at 11:07
  • Well, you could use hydrator->extract(), array_merge(), and hydrator->hydrate(), amybe with a bit of array_filter and/or array_intersect_key to keep it safe. – jkavalik Mar 14 '14 at 12:46

1 Answers1

0

Merge is not the only solution.

The JMSSerializerBundle includes an object constructor for Doctrine entities. When you enable this constructor, the deserialized entities are managed entities that can be persisted(with $em->persist($student)). The only attributes modified on the deserialized entity are the ones mentioned in the JSON from the request.

Here is how you can enable it.

franbenz
  • 696
  • 1
  • 10
  • 16