Symfony form unchanged field returns validation type error

Viewed 771

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:

<?php

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.

2 Answers

Edit: note that the following is true if field type is TextType, but IntegerType works fine with @Assert\Type("integer"). Which kinda renders my answer invalid/irrelevant...

You're using @Assert\Type("integer") annotation, but it means this:

  • value must be integer -- as a PHP type, like calling is_int($value)
  • and since data comes from form (and probably without any transformers, as I see in your code), it's type is string
  • and thus, validation always fails

What you need is @Assert\Type("numeric"):

  • it is equivalent of is_numeric($value)
  • down the line it will be converted to string when it reaches field of your entity

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.

Related