Как вернуть json закодированные ошибки формы в symfony
Я хочу создать веб-сервис, к которому я отправлю форму, а в случае ошибок возвращает список, закодированный jason, который сообщает мне, какое поле является неправильным.
в настоящее время я получаю только список сообщений об ошибках, но не идентификатор html или имя полей с ошибками
здесь мой текущий код
public function saveAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new TaskType(), new Task());
$form->handleRequest($request);
$task = $form->getData();
if ($form->isValid()) {
$em->persist($task);
$em->flush();
$array = array( 'status' => 201, 'msg' => 'Task Created');
} else {
$errors = $form->getErrors(true, true);
$errorCollection = array();
foreach($errors as $error){
$errorCollection[] = $error->getMessage();
}
$array = array( 'status' => 400, 'errorMsg' => 'Bad Request', 'errorReport' => $errorCollection); // data to return via JSON
}
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
}
это даст мне ответ вроде
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"Task cannot be blank",
"Task date needs to be within the month"
}
}
но я действительно хочу что-то вроде
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
Как я могу это достичь?
Ответы
Ответ 1
Наконец-то я нашел решение этой проблемы , для этого потребовалось только небольшое исправление, чтобы соответствовать последним изменениям symfony, и это сработало как шарм:
Исправление состоит в замене строки 33
if (count($child->getIterator()) > 0) {
с
if (count($child->getIterator()) > 0 && ($child instanceof \Symfony\Component\Form\Form)) {
потому что, с введением в symfony формы \Button, будет возникать несоответствие типа в функции сериализации, которая всегда ожидает экземпляр формы \Form.
Вы можете зарегистрировать его как услугу:
services:
form_serializer:
class: Wooshii\SiteBundle\FormErrorsSerializer
а затем используйте его, как предлагает автор:
$errors = $this->get('form_serializer')->serializeFormErrors($form, true, true);
Ответ 2
Я использую это, он работает спокойно:
/**
* List all errors of a given bound form.
*
* @param Form $form
*
* @return array
*/
protected function getFormErrors(Form $form)
{
$errors = array();
// Global
foreach ($form->getErrors() as $error) {
$errors[$form->getName()][] = $error->getMessage();
}
// Fields
foreach ($form as $child /** @var Form $child */) {
if (!$child->isValid()) {
foreach ($child->getErrors() as $error) {
$errors[$child->getName()][] = $error->getMessage();
}
}
}
return $errors;
}
Ответ 3
Это делает трюк для меня
$errors = [];
foreach ($form->getErrors(true, true) as $formError) {
$errors[] = $formError->getMessage();
}
Ответ 4
PHP имеет ассоциативные массивы, между тем у JS есть две разные структуры данных: объект и массивы.
JSON, который вы хотите получить, не является законным и должен быть:
{
"status":400,
"errorMsg":"Bad Request",
"errorReport": {
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
Итак, вы можете сделать что-то вроде этого, чтобы создать свою коллекцию:
$errorCollection = array();
foreach($errors as $error){
$errorCollection[$error->getId()] = $error->getMessage();
}
(предполагается, что метод getId() существует на объектах $error)
Ответ 5
Читая ответы других людей, я в итоге улучшил его до своих потребностей. Я использую это в Symfony 3.4.
Для использования в таком контроллере:
$formErrors = FormUtils::getErrorMessages($form);
return new JsonResponse([
'formErrors' => $formErrors,
]);
С этим кодом в отдельном классе Utils
<?php
namespace MyBundle\Utils;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
class FormUtils
{
/**
* @param FormInterface $form
* @return array
*/
public static function getErrorMessages(FormInterface $form)
{
$formName = $form->getName();
$errors = [];
/** @var FormError $formError */
foreach ($form->getErrors(true, true) as $formError) {
$name = '';
$thisField = $formError->getOrigin()->getName();
$origin = $formError->getOrigin();
while ($origin = $origin->getParent()) {
if ($formName !== $origin->getName()) {
$name = $origin->getName() . '_' . $name;
}
}
$fieldName = $formName . '_' . $name . $thisField;
/**
* One field can have multiple errors
*/
if (!in_array($fieldName, $errors)) {
$errors[$fieldName] = [];
}
$errors[$fieldName][] = $formError->getMessage();
}
return $errors;
}
}