Symfony 表单:如何准确知道哪个字段导致错误

Symfony form: how to know precisely which field cause an error

我必须解决一个关于 Symfony 表单验证的问题,它由 30 个子表单组成,每个子表单由 3 个实体组成,每个实体有大约 20-25 个字段。所以这个单一的表格包含超过1800个字段:-(.

在验证时,编写这种丑陋表单的开发人员会像这样在一行中检查它:

if ($form->isValid()) {
    [...]
}

如果表单无效,在 twig 模板中,他只写:

{{ form_errors(form) }}

因此,如果我使用当前值加载表单,并在不进行任何修改的情况下提交,验证将失败,并重复两次相同的 Symfony 默认消息:

This value should not be blank.

This value should not be blank.

但我不知道 1800 多个字段中的哪个字段导致错误,而且我没有找到如何向 Symfony 询问给定错误,即导致错误的字段。

我怎么知道哪个字段导致了错误?


编辑:我听从了亚历山大的建议并且:

$errors = $form->getErrors() ;
foreach($errors as $key => $error) {
    var_dump($error);
}

只给了我两次:

class Symfony\Component\Form\FormError#1750 (3) {
    protected $messageTemplate => string(31) "This value should not be blank."
    protected $messageParameters => array(0) {}
    protected $messagePluralization => NULL
}

不知道它发生在哪里。

上创建一个 foreach
$form

参见 \vendor\symfony\symfony\src\Symfony\Component\Form\Form。php -> getErrors

示例:

        foreach ($form as $child) {
            /** @var FormInterface $child */
            if ($child->isSubmitted() && $child->isValid()) {
                continue;
            }

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

            if (0 === count($iterator)) {
                continue;
            }
            $child->getName(); // here is the name of field

            if ($flatten) {
                foreach ($iterator as $error) {
                    $errors[] = $error;
                }
            } else {
                $errors[] = $iterator;
            }
            var_dump($errors); // here are the errors of that field
        }

我很久以前在网上的某个地方发现了这个方法,我每天都在使用它:)

/**
 * @param FormInterface $form
 *
 * @return array
 */
public function getErrorsFromForm(FormInterface $form)
{
    $errors = [];

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

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

    return $errors;
}

也许它可以帮助您调试错误。

编辑:这是原始 SO 问题 Get all errors along with fields the error is connected to

您可以使用 XDEBUG 并查看 $failed 变量中的错误。

我不会准确回答你的问题,即使我明白你想要什么和你想做什么,我也会建议你另一种(也许更好)的方式。

你的错误信息This value should not be blank不是Symfony的默认错误信息,它是Doctrine默认的注释错误信息@Assert\NotBlank。当然,您可以为实体上使用的每个字段自定义此错误消息。只需以这种方式在括号中添加您的消息:

/**
 * @var \DateTime $startDate
 *
 * @Assert\NotBlank(message="The start date should not be blank/is mandatory.")
 * @ORM\Column(name="startDate", type="date", nullable = false)
 */
private $startDate;

我知道您正在处理其他人的代码,有很多实体和字段,但如果您花时间替换大部分默认消息,现在和以后都可以为您节省很多时间。

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