Search code examples
phpsymfonysymfony-formssymfony-3.4

handleRequest() with PATCH method


To avoid using multiple FormType files, I'm submitting a form with PATCH method.
But symfony handleRequest() doesn't submit because there is a difference in method between the form config and the request.

First, setting form method in controller (to be able to submit)

$form=$this->createForm(UtilisateurType::class, $utilisateur, array(
    'action'=>$this->generateUrl('security_edit_user', array('id'=>$utilisateur->getId())),
    'method'=>'POST',
));
$form->handleRequest($request);

Then overwritting form method in twig when submitted

<form action="{{ form.vars.action }}" method="{{ form.vars.method }}" name="{{ form.vars.name }}" enctype="multipart/form-data">
    <!-- editor-fold -->
    <input name="_method" type="hidden" value="PATCH">
    <!-- editor-fold -->
</form>

The problem lie in handleRequest() function (vendor/symfony/symfony/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php).
The function will compare the form method and the request method, and prevent submit if they're different.

$method = $form->getConfig()->getMethod();
if ($method !== $request->getMethod()) {
    return;
}

Thus, I would like to know the reason behind this condition. Why does Symfony check if the methods are the same for the form and the request.

Then, is it possible to correct/bypass this? How would you recommand to do it?


Solution

  • Usually, when you want to use REST-ish approach, you would want to turn away from forms as much as possible (in traditional terms). As you well noticed, traditional forms only support POST and GET methods so PATCH will not work.

    Alternately, what you can do is

    • on client side, maintain JSON representation of your domain object
    • implement two-way binding (optional)
    • do not submit form but rather fire up a new PATCH HTTP request to your server containing JSON of new state

    Your server side should not handleRequest anymore, but instead $form->submit($data). The $data should be deserialized JSON from request body (if any). If you feel super lazy, there is a bundle for doing just that: qandidate-labs/symfony-json-request-transformer :)

    With this, you circumvent form limitation of POST/GET, but you still retain validation logic.

    Hope this helps...