how to return json encoded form errors in symfony

16,909

Solution 1

I've finally found the solution to this problem here, it only needed a small fix to comply to latest symfony changes and it worked like a charm:

The fix consists in replacing line 33

if (count($child->getIterator()) > 0) {

with

if (count($child->getIterator()) > 0 && ($child instanceof \Symfony\Component\Form\Form)) {

because, with the introduction in symfony of Form\Button, a type mismatch will occur in serialize function which is expecting always an instance of Form\Form.

You can register it as a service:

services:
form_serializer:
    class:        Wooshii\SiteBundle\FormErrorsSerializer

and then use it as the author suggest:

$errors = $this->get('form_serializer')->serializeFormErrors($form, true, true);

Solution 2

I am using this, it works quiet well:

/**
 * List all errors of a given bound form.
 *
 * @param Form $form
 *
 * @return array
 */
protected function getFormErrors(Form $form)
{
    $errors = array();

    // Global
    foreach ($form->getErrors() as $error) {
        $errors[$form->getName()][] = $error->getMessage();
    }

    // Fields
    foreach ($form as $child /** @var Form $child */) {
        if (!$child->isValid()) {
            foreach ($child->getErrors() as $error) {
                $errors[$child->getName()][] = $error->getMessage();
            }
        }
    }

    return $errors;
}

Solution 3

This does the trick for me

 $errors = [];
 foreach ($form->getErrors(true, true) as $formError) {
    $errors[] = $formError->getMessage();
 }

Solution 4

PHP has associative arrays, meanwhile JS has 2 different data structures : object and arrays.

The JSON you want to obtain is not legal and should be :

{
"status":400,
"errorMsg":"Bad Request",
"errorReport": {
        "taskfield" : "Task cannot be blank",
        "taskdatefield" : "Task date needs to be within the month"
    }
}

So you may want to do something like this to build your collection :

$errorCollection = array();
foreach($errors as $error){
     $errorCollection[$error->getId()] = $error->getMessage();
}

(assuming the getId() method exist on $error objects)

Share:
16,909

Related videos on Youtube

SimonQuest
Author by

SimonQuest

Updated on June 07, 2022

Comments

  • SimonQuest
    SimonQuest almost 2 years

    I want to create a webservice to which I submit a form, and in case of errors, returns a JSON encoded list that tells me which field is wrong.

    currently I only get a list of error messages but not an html id or a name of the fields with errors

    here's my current code

    public function saveAction(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
    
        $form = $this->createForm(new TaskType(), new Task());
    
        $form->handleRequest($request);
    
        $task = $form->getData();
    
        if ($form->isValid()) {
    
            $em->persist($task);
            $em->flush();
    
            $array = array( 'status' => 201, 'msg' => 'Task Created'); 
    
        } else {
    
            $errors = $form->getErrors(true, true);
    
            $errorCollection = array();
            foreach($errors as $error){
                   $errorCollection[] = $error->getMessage();
            }
    
            $array = array( 'status' => 400, 'errorMsg' => 'Bad Request', 'errorReport' => $errorCollection); // data to return via JSON
        }
    
        $response = new Response( json_encode( $array ) );
        $response->headers->set( 'Content-Type', 'application/json' );
    
        return $response;
    }
    

    this will give me a response like

    {
    "status":400,
    "errorMsg":"Bad Request",
    "errorReport":{
            "Task cannot be blank",
            "Task date needs to be within the month"
        }
    }
    

    but what I really want is something like

    {
    "status":400,
    "errorMsg":"Bad Request",
    "errorReport":{
            "taskfield" : "Task cannot be blank",
            "taskdatefield" : "Task date needs to be within the month"
        }
    }
    

    How can I achieve that?

  • SimonQuest
    SimonQuest almost 10 years
    for id or name of the field I mean something that I can use to target the field in form... like an html id or name of the field.
  • Delapouite
    Delapouite almost 10 years
    If your iterate with foreach($errors as $key => $error), isn't $key what you're looking for?
  • SimonQuest
    SimonQuest almost 10 years
    no, it would simply be a numerical index... I need something to target the html element
  • rolebi
    rolebi almost 10 years
    @SimonQuest This answer (and subsequent) may help you.
  • SimonQuest
    SimonQuest almost 10 years
    Unfortunately this didn't work for me, at least not the way I wanted. Thanks you very much for answering
  • SimonQuest
    SimonQuest almost 10 years
    it doesn't traverse properly the form structure if it's not a simple one and it's not returning the input fields ids/names. Maybe My explanation of the problem wasn't clear enough. Try the solution I've found, you'll understand.
  • COil
    COil almost 10 years
    Yes indeed, it's for one level forms only.
  • Yonedev
    Yonedev over 5 years
    Perfect solution :)