5

我正在使用 Symfony2 表单来验证对 API 的 POST 和 PUT 请求。表单处理将请求数据绑定到底层实体,然后验证实体。除了收集错误之外,一切都运行良好。我正在使用 FOSRestBundle,如果验证失败,我会抛出一个带有 400 状态代码的 Symfony\Component\HttpKernel\Exception\HttpException 和一条包含表单错误消息的消息。FOSRestBundle 处理将其转换为 JSON 响应。我必须执行所有这些操作的控制器方法如下所示(所有字段将它们的错误冒泡到表单中):

protected function validateEntity(AbstractType $type, $entity, Request $request)
{
    $form = $this->createForm($type, $entity);
    $form->bind($request);
    if (! $form->isValid()) {
        $message = ['Invalid parameters passed.'];
        foreach ($form->getErrors() as $error) {
            $message[] = $error->getMessage();
        }
        throw new HttpException(Codes::HTTP_BAD_REQUEST, implode("\n", $message));
    }
}

我遇到的问题是,当我通过 $form->getErrors() 收集表单级错误时,我只能访问错误消息,而不是错误连接到的字段的名称。当 POST 或 PUT 参数对应于相关实体的 id 时,这是一个特殊问题。如果提交了无效值,则错误消息只是“此值无效”,这在这种情况下不是很好。理想情况下,我想做以下任一项:

  • 对于每个错误,获取它所连接的字段名称,以便我可以格式化消息,例如“字段名称:错误消息”
  • 如果这不可能,是否可以为无效实体类型自定义错误消息,以便显示比“此值无效”更好的内容?
4

7 回答 7

13

对于 symfony >= 2.2

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();
    foreach ($form->getErrors() as $key => $error) {
        $template = $error->getMessageTemplate();
        $parameters = $error->getMessageParameters();

        foreach ($parameters as $var => $value) {
            $template = str_replace($var, $value, $template);
        }

        $errors[$key] = $template;
    }
    if ($form->count()) {
        foreach ($form as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    }
    return $errors;
}
于 2013-07-24T07:57:05.550 回答
8

使用此功能可获取绑定表单后的所有错误消息。

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();
    foreach ($form->getErrors() as $key => $error) {
        $template = $error->getMessageTemplate();
        $parameters = $error->getMessageParameters();

        foreach($parameters as $var => $value){
            $template = str_replace($var, $value, $template);
        }

        $errors[$key] = $template;
    }
    if ($form->hasChildren()) {
        foreach ($form->getChildren() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    }
    return $errors;
}
于 2012-12-07T12:24:40.830 回答
5

您可以以getErrorsAsString方法为例来获得您想要的功能。您还必须在表单字段上设置invalid_message选项以更改This value is invalid消息。

于 2012-09-23T19:55:55.670 回答
3

尝试了一切,没有按我的意愿工作。
这是我对 Symfony 4 的尝试(这也是为什么框架中默认情况下不可用的原因,这超出了我的理解,就像他们不希望我们使用带有 ajax 的表单:thinking :)

它返回一个消息数组,键是 dom id,因为它将由 Symfony 生成(它也适用于数组)

//file FormErrorsSerializer.php
<?php

namespace App\Helper;

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

class FormErrorsSerializer
{
    public function getFormErrors(Form $form): array
    {
        return $this->recursiveFormErrors($form->getErrors(true, false), [$form->getName()]);
    }

    private function recursiveFormErrors(FormErrorIterator $formErrors, array $prefixes): array
    {
        $errors = [];

        foreach ($formErrors as $formError) {
            if ($formError instanceof FormErrorIterator) {
                $errors = array_merge($errors, $this->recursiveFormErrors($formError, array_merge($prefixes, [$formError->getForm()->getName()])));
            } elseif ($formError instanceof FormError) {
                $errors[implode('_', $prefixes)][] = $formError->getMessage();
            }
        }

        return $errors;
    }
}
于 2018-09-11T18:38:14.437 回答
2

对于 Symfony 4.x+(可能适用于较低版本)。

// $form = $this->createForm(SomeType::class);
// $form->submit($data);
// if (!$form->isValid()) {
//     var_dump($this->getErrorsFromForm($form));
// }

private function getErrorsFromForm(FormInterface $form, bool $child = false): array
{
    $errors = [];

    foreach ($form->getErrors() as $error) {
        if ($child) {
            $errors[] = $error->getMessage();
        } else {
            $errors[$error->getOrigin()->getName()][] = $error->getMessage();
        }
    }

    foreach ($form->all() as $childForm) {
        if ($childForm instanceof FormInterface) {
            if ($childErrors = $this->getErrorsFromForm($childForm, true)) {
                $errors[$childForm->getName()] = $childErrors;
            }
        }
    }

    return $errors;
}
于 2019-10-06T11:17:06.327 回答
1

我创建了一个包来帮助解决这个问题。

你可以在这里得到它:

https://github.com/Ex3v/FormErrorsBundle

欢迎投稿。干杯。

于 2014-06-08T18:30:53.430 回答
1

我需要一个解决方案来获取所有嵌套表单的所有错误的关联数组,其中键格式化,因此它表示相应表单字段元素的文档 ID:

namespace Services;

use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormErrorIterator;

/**
 * Class for converting forms.
 */
class FormConverter
{
    /**
     * Gets all errors of a form as an associative array with keys representing the dom id of the form element.
     *
     * @param Form $form
     * @param bool $deep Whether to include errors of child forms as well
     * @return array
     */
    public function errorsToArray(Form $form, $deep = false) {
        return $this->getErrors($form, $deep);
    }

    /**
     * @param Form $form
     * @param bool $deep
     * @param Form|null $parentForm
     * @return array
     */
    private function getErrors(Form $form, $deep = false, Form $parentForm = null) {
        $errors = [];

        if ($deep) {
            foreach ($form as $child) {
                if ($child->isSubmitted() && $child->isValid()) {
                    continue;
                }

                $iterator = $child->getErrors(true, false);

                if (0 === count($iterator)) {
                    continue;
                } elseif ($iterator->hasChildren()) {
                    $childErrors = $this->getErrors($iterator->getChildren()->getForm(), true, $child);
                    foreach ($childErrors as $key => $childError) {
                        $errors[$form->getName() . '_' . $child->getName() . '_' .$key] = $childError;
                    }
                } else {
                    foreach ($iterator as $error) {
                        $errors[$form->getName() . '_' . $child->getName()][] = $error->getMessage();
                    }
                }
            }
        } else {
            $errorMessages = $this->getErrorMessages($form->getErrors(false));
            if (count($errorMessages) > 0) {
                $formName = $parentForm instanceof Form ? $parentForm->getName() . '_' . $form->getName() : $form->getName();
                $errors[$formName] = $errorMessages;
            }
        }

        return $errors;
    }

    /**
     * @param FormErrorIterator $formErrors
     * @return array
     */
    private function getErrorMessages(FormErrorIterator $formErrors) {
        $errorMessages = [];
        foreach ($formErrors as $formError) {
            $errorMessages[] = $formError->getMessage();
        }

        return $errorMessages;
    }
}
于 2017-07-21T16:14:00.587 回答