ganchito55
ganchito55

Reputation: 3607

Deserialize entity with null id and doctrine constructor

I'm having many problems when I receive an entity to deserialize with null id.

My JMS Serializer configuration file is:

jms_serializer:
    handlers:
        datetime:
            default_format: Y-m-d\TH:i:s+
        array_collection:
            initialize_excluded: false
    property_naming:
        id: jms_serializer.identical_property_naming_strategy
        separator: ''
        lower_case: false
        enable_cache: true
    object_constructors:
        doctrine:
            fallback_strategy: "fallback" 

So, when the entity has an id field, it tries to retrieve the entity with that id from database via doctrine (something like $repository->find($id)).

If the Id exists, it retrieves the entity filled. If it doesn't exist return an exception. The problem is that when I receive a JSON with an entity to persist, the id field is null and it tries to find an entity in the database with ìd==null, so it throws an exception.

I have tried to change the fallback_strategy to: "null","exception" or "fallback" without success.

Edit: the Controller where it happens

protected function post(Request $request)
{
    $content = $request->getContent();
    try {
        $entity = $this->get('jms_serializer')->deserialize($content, 'App\Entity\Service', 'json');
    } catch (\Exception $e){
        throw new ValidationException($e);
    }
 ....
}

I put a try-catch block to capture and log the exception with a custom class.

I hope you can help me,

Thanks

Upvotes: 1

Views: 1001

Answers (1)

Antoine Galluet
Antoine Galluet

Reputation: 320

It's more a workaround but for my CRUD controllers I prefer to use form to deserialize my objects. It allows me to be more flexible, I can have different form of payload for the same entity and I can check in a better way my payload.

The common form looks like this (you have to adapt it to your entity)

class YourEntityType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('description')
            ...
    }
}

And in the controller :

protected function post(Request $request)
{
    $yourEntity = new YourEntity();

    $form = $this->createForm(YourEntityType::class, $yourEntity);
    $form->submit($request->request->all());

    if ($form->isSubmitted() && $form->isValid()) {
        $em->persist($yourEntity);
        $em->flush();

        return $yourEntity;
    }

    return $form;
}

Don't know if it's gonna fit with your project but that the cleanest way I know and it bypass you id issue because you don't have to put it in your form.

Upvotes: 1

Related Questions