phpsymfonysymfony-forms

Symfony 4.3 Multiple ChoiceType can only add values and not remove when using PATCH


Given form:

...
        $builder
            ->add('testArray', ChoiceType::class, [
                'choices' => ['ROLE_ADMIN' => 'ROLE_ADMIN', 'ROLE_USER' => 'ROLE_USER'],
                'expanded' => true,
                'multiple' => true
            ])
        ;

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => TestEntity::class,
            'csrf_protection' => false,
            'method' => 'PATCH'
        ]);
    }

...

And entity:

...
    /**
     * @ORM\Column(type="simple_array", nullable=true)
     */
    private $testArray = [];

    public function getTestArray(): ?array
    {
        return $this->testArray;
    }

    public function setTestArray(?array $testArray): self
    {
        $this->testArray = $testArray;

        return $this;
    }
...

When submitting the form by adding values... everything works fine. But when removing values... the values are not removed, and the setter is never called.

Strangely, switching the form method to GET fixes this.

What's going on?

Here's a controller that reproduces this issue:

    /**
     * @Route("/{id}/edit", name="test_entity_edit", methods={"GET","POST","PATCH"})
     */
    public function edit(Request $request, TestEntity $testEntity): Response
    {
        $form = $this->createForm(TestEntityType::class, $testEntity);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->getDoctrine()->getManager()->flush();


            return $this->redirectToRoute('test_entity_index', [
                'id' => $testEntity->getId(),
            ]);
        }

        return $this->render('test_entity/edit.html.twig', [
            'test_entity' => $testEntity,
            'form' => $form->createView(),
        ]);
    }

Testing using POST this works perfectly. But using PATCH it fails. All other fields update. And adding to the array works. But removing from the array doesn't. I've added the relevant PATCH code above and updated the title to clarify the question.


Solution

  • It appears that PATCH is ambiguous when it comes to arrays and there are various ways of handling the sent data.

    Symfony will detect a PATCH and not $clearMissing when calling submit() (not empty the fields in the entity that are missing from the data). When it comes to an array, this is ambigious.

    To deal with this I've moved away from using PATCH to update a user entity and moved to this solution Symfony2: Edit user without having password

    Which essentially uses two different FormType's one to create the user, and another to edit it. Each form type uses a different validation group. Allowing to edit a user without submitting or clearing the users password.