web-dev-qa-db-ja.com

symfonyでjsonエンコードされたフォームエラーを返す方法

フォームを送信する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"
    }
}

どうすればそれを達成できますか?

25
SimonQuest

私はようやくこの問題の解決策を見つけました 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);
16
SimonQuest

私はこれを使用していますが、静かに動作します:

/**
 * 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;
}
26
COil

これは私にとってはトリックです

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

PHPには連想配列がありますが、JSには2つの異なるデータ構造(オブジェクトと配列)があります。

取得したい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();
}

(getId()メソッドが$ errorオブジェクトに存在すると仮定)

1
Delapouite

他の人の答えを読むことで、自分のニーズに合わせて改善することができました。 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;
    }
}
0
Julesezaar