How do I get Symfony forms to work with a REST API?

11,859

Solution 1

It would be helpful if you could provide the whole code of your CreditCardType class as well as the complete POST data and the validation errors from your form.

Anyway this are the things I found to be the reason for form submit failures:

  • Submit incomplete data: if you have a field on your CerditCardType form that is absent on your POST request, make sure it has the option 'required' set to false.
  • Form name: make sure all your fields are wrapped by a property named after your form name (the name you provide on your CreditCardType::getName() method). In your case I assume that is "credit_card".
  • Only post the fields defined in your CreditCardType class. If you post a parameter which doesn't match any field of your form you will get a validation error like "This form shouldn't have any extra fields" or something like that.

Anyway if you provide more information I'd be glad to help more.

UPDATE:

Ok, I think your problem is you are posting your data as a JSON string and the handleRequest() method is not getting any data because Symfony doesn't know it should be decoded from the request's body (it expects the data to be sent either as $_GET or $_POST parameters). So you have to do it on your own.

Instead of using the handleRequest() method you have to use the submit() method with the data you obtained by decoding the request content ($request->getContent()):

$request = $this->getRequest();
$cc = new CreditCard();
$form = $this->createForm(new CreditCardType(), $cc);

// Decode de JSON input
$data = json_decode($request->getContent(), true);

// Post the data to the form
$form->submit($data);

if ($form->isValid()) {
  //...
}

Hope it helps now!

BTW if your are working on an RESTful implementation you should really consider using the FOSRestBundle bundle. It would handle for you all the formats conversion logic as well as routing, entities de/serialization, etc.

Solution 2

Your data isn't being passed to the form properly because you are passing in a request object that doesn't have the form name as a key.

When you create a form using Symfony it create the following type of array when POSTing..

"your_form_name": {         // Given that you forms `getName()` 
                            // returns "your_form_name"
    "field1": "value1",
    "field2": "value2"
}

When you use the handleRequest method it use the form name as the key like below (see github for the full code)..

if ('GET' === $method) {
        if ('' === $name) {
            $data = $_GET;
        } else {
            // Don't submit GET requests if the form's name does not exist
            // in the request
            if (!isset($_GET[$name])) {
                return;
            }

            $data = $_GET[$name];
        }
    } else {
        // ... same sort of stuff for $_POST, $_FILES, etc
    }

    // ...

    $form->submit($data, 'PATCH' !== $method);

This means that if you submit an array that doesn't contain the form name then it doesn't get submitted.

The way to get around that would be to use the submit() method instead and submit all of the data rather than the data with the form name key like..

$form->submit($request->request->all());    // $_POST

$form->submit($request->query->all());      // $_GET
Share:
11,859
Derick F
Author by

Derick F

SOreadytohelp

Updated on June 26, 2022

Comments

  • Derick F
    Derick F almost 2 years

    I'm currently trying to get symfony forms to work with my post and put rest api endpoint.

    Currently I have:

    $request = $this->getRequest();
    $cc = new CreditCard();
    $form = $this->createForm(new CreditCardType(), $cc);
    
    $form->handleRequest($request);
    
    if ($form->isValid()) {
      //...
    }
    

    However, the form is never valid. Looking into the problem, it seems that the form's isSubmitted field is false, so it never passes validation. Also, since this is an api call, I have the csrf_protection set to false in the creditcardtype.

    Here is an example of what data I'm having the user submit:

    {
      "credit_card": {
         "name" : "Example Name"
         ...
      }
    }
    

    How do I get this post/put request to be registered as submitted and have the form validator pass? Thanks.