如何在 symfony 中返回 json 编码格式错误

Posted

技术标签:

【中文标题】如何在 symfony 中返回 json 编码格式错误【英文标题】:how to return json encoded form errors in symfony 【发布时间】:2014-08-24 17:17:05 【问题描述】:

我想创建一个向其提交表单的 Web 服务,如果出现错误,则返回一个 JSON 编码列表,告诉我哪个字段是错误的。

目前我只得到错误消息列表,但没有 html id 或有错误的字段名称

这是我当前的代码

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;

这会给我一个类似的回应


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

但我真正想要的是类似的东西


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

我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

我正在使用它,它运行良好:

/**
 * 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;

【讨论】:

不幸的是,这对我不起作用,至少不是我想要的方式。非常感谢您的回答 如果它不是一个简单的表单结构并且它没有返回输入字段 ids/names,它就不会正确地遍历表单结构。也许我对问题的解释不够清楚。试试我找到的解决方案,你就会明白了。 是的,它只适用于一级表单。 完美解决方案:)【参考方案2】:

我终于找到了这个问题的解决方案here,它只需要一个小修复来符合最新的 symfony 更改,它就像一个魅力:

修复包括替换第 33 行

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

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

因为在 symfony 中引入 Form\Button 时,序列化函数会出现类型不匹配,该函数总是期望 Form\Form 的实例。

您可以将其注册为服务:

services:
form_serializer:
    class:        Wooshii\SiteBundle\FormErrorsSerializer

然后按照作者的建议使用它:

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

【讨论】:

【参考方案3】:

这对我有用

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

【讨论】:

【参考方案4】:

php 有关联数组,而 JS 有两种不同的数据结构:对象和数组。

你要获取的 JSON 是不合法的,应该是:


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

所以你可能想做这样的事情来建立你的收藏:

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

(假设 $error 对象上存在 getId() 方法)

【讨论】:

对于字段的 id 或名称,我的意思是我可以用它来定位表单中的字段...例如 html id 或字段名称。 如果您使用 foreach($errors as $key => $error) 进行迭代,您要查找的不是 $key 吗? 不,它只是一个数字索引...我需要一些东西来定位 html 元素 @SimonQuest 这个answer(及后续)可能会对您有所帮助。【参考方案5】:

通过阅读其他人的答案,我最终根据自己的需要对其进行了改进。我在 Symfony 3.4 中使用它。

在这样的控制器中使用:

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

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

在单独的 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;
    

【讨论】:

【参考方案6】:

这样就可以了。此静态方法通过调用$form-&gt;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;
    

结果如下:


    "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."
        
    

【讨论】:

以上是关于如何在 symfony 中返回 json 编码格式错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在PHP中返回Json数据

最佳实践以及如何在 Symfony2 中找到从 iOS AFNetworking 获取 POST 数据并在 GET 中返回 JSON?

如何在 Symfony2 中将 Json 绑定到实体中

如何使用 Symfony 编码 CSV

从 Symfony 中的控制器返回 JSON 数组

如何将 iOS 应用程序连接到 Symfony2 RESTful Webservice?