phpsymfonysymfony-forms

Symfony form unchanged field returns validation type error


Trying to update an entity, and submitting a field with a value that is unchanged results in a type error. What am I doing wrong?

Entity:

namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;
...
class User implements UserInterface
{
...

    /**
     * @ORM\Column(type="bigint", nullable=true)
     * @Groups({"default", "listing"})
     * @Assert\Type("integer")
     */
    private $recordQuota;

...

FormType:

<?php

namespace App\Form;

...

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
...
            ->add('recordQuota', IntegerType::class)
        ;
    }

...
}

Controller:

...
    /**
     * @Route("/api/user/{id}", name="editUser")
     * @Method({"PUT", "PATCH"})
     * @Rest\View()
     */
    public function updateAction(Request $request, User $user)
    {
        $form = $this->createForm(UserType::class, $user);
        $data = $request->request->get('user');
        $clearMissing = $request->getMethod() != 'PATCH';

        $form->submit($data, $clearMissing);


        if ($form->isSubmitted() && $form->isValid()) {
...

I'm using PostMan to submit form data. If the entity I am updating has a recordQuota of 1000, and I submit the form with a different value. It all works and updates.

But if I submit my form with recordQuota: 1000, which should leave the value unchanged I get an incorrect type error:

"recordQuota": {
    "errors": [
        "This value should be of type integer."
    ]
}

Additional info:

I am using $form->submit instead of handleRequest because I am using patch. So I need to be able to enable/disable $clearMissing. But even using handleRequest creates the same issue.

Even typecasting the recordQuota as int before passing it to the form still fails.

If I remove all of the type information from the Form and the Entity, I get "This value should be of type string" when actually making a change.


Solution

  • This was an issue with a combination of Symfony 4.3 validator auto_mapping described here: https://symfony.com/blog/new-in-symfony-4-3-automatic-validation

    And the maker bundle adding the wrong typecast to bigint fields.

    See here: https://github.com/symfony/maker-bundle/issues/429

    The answer was to change the getters and setters in the entity from:

        public function getRecordQuota(): ?int
        {
            return $this->recordQuota;
        }
    
        public function setRecordQuota(?int $recordQuota): self
        {
            $this->recordQuota = $recordQuota;
    
            return $this;
        }
    

    to

        public function getRecordQuota(): ?string
        {
            return $this->recordQuota;
        }
    
        public function setRecordQuota(?string $recordQuota): self
        {
            $this->recordQuota = $recordQuota;
    
            return $this;
        }
    

    Alternatively, one can turn off auto_mapping in the validator config.