Search code examples
symfonydoctrine-ormcascadefosrestbundlejmsserializerbundle

Symfony3 Related Entity not mapped back to parent on creation


I have 2 entities Client and Address with a OneToMany relationship.
When I create a new client with an address, it saves both the client and address but does not set the client_id on the address, it is NULL.

I am using fosrestbundle and jmsserializer and sending the data as a json object.

In my controller I have the following:

/**
 * @REST\POST("/clients", name="create_client")
 */
public function createClientAction(Request $request)
{
    $serializer = $this->get('jms_serializer');
    $client = $serializer->deserialize($request->getContent(), 'AppBundle\Entity\Client', 'json');

    $em = $this->getDoctrine()->getManager();
    $em->persist($client);
    $em->flush();

    return $this->view($client, 200);
}

Here is a simplified request payload:

{ "name" : "foo", "addresses" : [ { "zip" : "12345" } ]

In my database it creates a new client with name = foo along with an address with zip = 12345, however the field client_id is NULL

My entities are mapped as follows:

//Client.php
...
...
/**
 * @ORM\OneToMany(targetEntity="Address", mappedBy="client", cascade={"persist", "remove"})
 */ 
private $addresses;

//Address.php
...
...
/**
 * @ORM\ManyToOne(targetEntity="Client", inversedBy="addresses")
 *
 */
private $client;

update

I'm even more confused now, I just realized I do not have any getters/setters in my entities, yet I am able to get / set data.

I am guessing setting has something to do with serializer->deserialize. I have the following in my services:

jms_serializer.object_constructor:
    alias: jms_serializer.doctrine_object_constructor
    public: false

And getting has something to do with the fosrestbundle. Here is the get route:

/**
 * @REST\GET("/clients/{client}", name="get_client")
 */
public function getClientAction(Request $request, Client $client)
{
    return $this->view($client, 200);
}

Solution

  • Apparently I needed to merge and not persist the entity.

    I updated the route:

    $em = $this->getDoctrine()->getManager();
    $em->merge($client);
    $em->flush();
    

    and the Client entity:

    /**
     * @ORM\OneToMany(targetEntity="Address", mappedBy="client", cascade={"persist", "remove", "merge"})
     */ 
    private $addresses;
    

    Seems to be working now!