【问题标题】:Get all errors along with fields the error is connected to获取所有错误以及错误连接到的字段
【发布时间】:2012-09-15 07:04:34
【问题描述】:

我正在使用 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 时,这是一个特殊问题。如果提交了无效值,则错误消息只是“此值无效”,这在这种情况下不是很好。理想情况下,我想执行以下任一操作:

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

【问题讨论】:

    标签: php symfony symfony-2.1


    【解决方案1】:

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

    【讨论】:

    • 适用于 Symfony 3.4。
    【解决方案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->hasChildren()) {
            foreach ($form->getChildren() as $child) {
                if (!$child->isValid()) {
                    $errors[$child->getName()] = $this->getErrorMessages($child);
                }
            }
        }
        return $errors;
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 谢谢。不知何故,我错过了文档中的 invalid_message 选项。正是我需要的。
      • 警告:getErrorsAsString 已弃用,将在 3.0 中删除
      • 自 3.0 起更简单:$form->getErrors(true, false);得到子错误
      【解决方案4】:

      尝试了所有方法,但没有按我的意愿工作。
      这是我对 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;
          }
      }
      

      【讨论】:

        【解决方案5】:

        适用于 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;
        }
        

        【讨论】:

          【解决方案6】:

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

          你可以在这里得到它:

          https://github.com/Ex3v/FormErrorsBundle

          欢迎投稿。干杯。

          【讨论】:

            【解决方案7】:

            我需要一个解决方案来获取所有嵌套表单的所有错误的关联数组,其中键格式化,因此它表示相应表单字段元素的文档 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;
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-03-14
              • 2013-11-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-07-18
              • 1970-01-01
              相关资源
              最近更新 更多