简体   繁体   English

如何在 symfony 中返回 json 编码的表单错误

[英]how to return json encoded form errors in symfony

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.我想创建一个我提交表单的网络服务,如果出现错误,则返回一个 JSON 编码的列表,告诉我哪个字段是错误的。

currently I only get a list of error messages but not an html id or a name of the fields with errors目前我只得到一个错误消息列表,而不是一个 html id 或有错误的字段的名称

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?我怎样才能做到这一点?

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;
}

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:我终于在这里找到了这个问题的解决方案,它只需要一个小的修复来符合最新的 symfony 更改,它就像一个魅力:

The fix consists in replacing line 33修复包括替换第 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.因为,随着 symfony 中 Form\\Button 的引入,序列化函数中会发生类型不匹配,该函数总是期望 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);

This does the trick for me这对我有用

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

PHP has associative arrays, meanwhile JS has 2 different data structures : object and arrays. PHP 有关联数组,而 JS 有两种不同的数据结构:对象和数组。

The JSON you want to obtain is not legal and should be :您要获取的 JSON 不合法,应该是:

{
"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) (假设 $error 对象上存在 getId() 方法)

By reading other people's answers I ended up improving it to my needs.通过阅读其他人的答案,我最终根据自己的需要对其进行了改进。 I use it in Symfony 3.4.我在 Symfony 3.4 中使用它。

To be used in a controller like this:要在这样的控制器中使用:

$formErrors = FormUtils::getErrorMessages($form);

return new JsonResponse([
    'formErrors' => $formErrors,
]);

With this code in a separate Utils class在单独的 Utils 类中使用此代码

<?php

namespace MyBundle\Utils;

use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;

class FormUtils
{
    /**
     * @param FormInterface $form
     * @return array
     */
    public static function getErrorMessages(FormInterface $form)
    {
        $formName = $form->getName();
        $errors = [];

        /** @var FormError $formError */
        foreach ($form->getErrors(true, true) as $formError) {
            $name = '';
            $thisField = $formError->getOrigin()->getName();
            $origin = $formError->getOrigin();
            while ($origin = $origin->getParent()) {
                if ($formName !== $origin->getName()) {
                    $name = $origin->getName() . '_' . $name;
                }
            }
            $fieldName = $formName . '_' . $name . $thisField;
            /**
             * One field can have multiple errors
             */
            if (!in_array($fieldName, $errors)) {
                $errors[$fieldName] = [];
            }
            $errors[$fieldName][] = $formError->getMessage();
        }

        return $errors;
    }
}

This will do the trick.这将解决问题。 This static method runs recursively through the Symfony\\Component\\Form\\FormErrorIterator delivered by calling $form->getErrors(true, false) .这个静态方法通过调用$form->getErrors(true, false)传递的Symfony\\Component\\Form\\FormErrorIterator递归运行。

<?php


namespace App\Utils;


use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormErrorIterator;

class FormUtils
{
    public static function generateErrorsArrayFromForm(FormInterface $form)
    {
        $result = [];
        foreach ($form->getErrors(true, false) as $formError) {
            if ($formError instanceof FormError) {
                $result[$formError->getOrigin()->getName()] = $formError->getMessage();
            } elseif ($formError instanceof FormErrorIterator) {
                $result[$formError->getForm()->getName()] = self::generateErrorsArrayFromForm($formError->getForm());
            }
        }
        return $result;
    }
}

Here is the result :结果如下:

{
    "houseworkSection": "All the data of the housework section must be set since the section has been requested.",
    "foodSection": {
        "requested": {
            "requested": "This value is not valid."
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM