Получите все ошибки вместе с полями, с которыми связана ошибка


Я использую формы Symfony2 для проверки сообщений и отправки запросов в API. Форма обрабатывает привязку данных запроса к базовой сущности и последующую проверку сущности. Все работает довольно хорошо, за исключением сбора ошибок. Я использую 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 соответствует идентификатору связанного объекта. Если отправлено неверное значение, сообщения об ошибках ибо это просто "Это значение недействительно", что не очень хорошо в данном контексте. В идеале я хотел бы сделать одно из следующих действий:

  • Для каждой ошибки найдите имя поля, к которому она подключена, чтобы я мог отформатировать сообщение примерно так: "имя поля: сообщение об ошибке"
  • Если это невозможно, можно ли настроить сообщение об ошибке для недопустимого типа сущности так, чтобы отображалось что-то лучшее, чем "Это значение недопустимо"?
Author: Jeremy, 2012-09-23

6 answers

Вы можете взять Метод geterrorsasstring в качестве примера, чтобы получить желаемую функциональность. Также вам необходимо установить опцию invalid_message в поле формы, чтобы изменить сообщение This value is invalid.

 5
Author: Mun Mun Das, 2015-03-27 12:41:01

И для 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;
}
 11
Author: Daniel Espendiller, 2013-07-24 07:57:05

Используйте эту функцию, чтобы получить все сообщения об ошибках после привязки формы.

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;
}
 9
Author: Julfiker, 2012-12-07 12:40:50

Я создал пакет, чтобы помочь в решении этой проблемы.

Вы можете получить его здесь:

Https://github.com/Ex3v/FormErrorsBundle

Вклад приветствуется. Ваше здоровье.

 1
Author: ex3v, 2014-06-08 18:30:53

Мне нужно было решение, чтобы получить ассоциативный массив всех ошибок всех вложенных форм с ключом, сформированным таким образом, чтобы он представлял идентификатор документа соответствующего элемента поля формы:

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;
    }
}
 0
Author: reneblue, 2017-07-21 16:14:00

Перепробовал все, но ничего не получалось так, как я хотел.
Вот моя попытка с Symfony 4 (также, почему, черт возьми, это недоступно по умолчанию в фреймворке, мне непонятно, как будто они не хотят, чтобы мы использовали формы с ajax:мышление:)

Он возвращает массив сообщений с ключами, являющимися идентификатором dom, как это было бы сгенерировано 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;
    }
}
 0
Author: C Alex, 2018-09-12 13:07:15