获取所有错误以及错误所连接的字段

时间:2012-09-23 17:32:51

标签: php symfony symfony-2.1

我正在使用Symfony2表单来验证对API的POST和PUT请求。表单处理将请求数据绑定到底层实体,然后验证实体。除收集错误外,一切都很顺利。我正在使用FOSRestBundle并抛出一个Symfony \ Component \ HttpKernel \ Exception \ HttpException,其中包含400状态代码和一条包含表单错误消息的消息,如果验证失败。 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时,这是一个特殊问题。如果提交的值无效,则该错误消息只是“此值无效”,在此上下文中不是很好。理想情况下,我想做以下任何一种情况:

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

7 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分: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;
}

答案 2 :(得分:5)

您可以将getErrorsAsString方法作为示例来获取所需的功能。您还必须在表单字段中设置invalid_message选项以更改This value is invalid消息。

答案 3 :(得分:1)

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

你可以在这里得到它:

https://github.com/Ex3v/FormErrorsBundle

欢迎捐款。欢呼声。

答案 4 :(得分: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;
    }
}

答案 5 :(得分:1)

尝试了所有内容,但没有达到我想要的效果。
这是我对Symfony 4的尝试(这也是为什么默认情况下框架中没有该死的东西超出了我,这就像他们不希望我们使用带有ajax的表单一样:thinking :)

它返回一个消息数组,密钥是由Symfony生成的dom id(它也适用于数组)

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

答案 6 :(得分:0)

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