我正在使用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时,这是一个特殊问题。如果提交的值无效,则该错误消息只是“此值无效”,在此上下文中不是很好。理想情况下,我想做以下任何一种情况:
答案 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)
答案 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;
}