Symfony2: Jak uzyskać błędy walidacji formularza po powiązaniu żądania z formularzem

110

Oto mój saveActionkod (gdzie formularz przekazuje dane)

public function saveAction()
{
    $user = OBUser();

    $form = $this->createForm(new OBUserType(), $user);

    if ($this->request->getMethod() == 'POST')
    {
        $form->bindRequest($this->request);
        if ($form->isValid())
            return $this->redirect($this->generateUrl('success_page'));
        else
            return $this->redirect($this->generateUrl('registration_form'));
    } else
        return new Response();
}

Moje pytanie brzmi: jak mogę uzyskać błędy w przypadku $form->isValid()zwrotów false?

putolaruan
źródło

Odpowiedzi:

117

Masz na to dwa sposoby:

  • nie przekierowuj użytkownika w przypadku błędu i nie wyświetlaj go {{ form_errors(form) }}w pliku szablonu
  • dostęp do tablicy błędów jako $form->getErrors()
nefo_x
źródło
22
Zrobiłem drugą rzecz, którą zasugerowałeś, ale form-> getErrors () zwróciło pustą tablicę.
putolaruan
2
Zrobiłem też pierwszy (z szablonami php <? Php echo $ view ['form'] -> błędy ($ form)?>), Ale nadal jest pusty!
putolaruan
59
@mives Musisz ustawić wartość error_bubblingtrue w swoim typie formularza, jawnie ustawiając opcję dla każdego pola.
kgilden,
5
Jeśli używasz niestandardowych walidatorów, Symfony nie zwraca błędów generowanych przez te walidatory w $ form-> getErrors ().
Jay Sheth,
13
Możesz również $form->getErrors(true)dołączyć błędy w formularzach podrzędnych
Chris
103

Symfony 2.3 / 2.4:

Ta funkcja pobiera wszystkie błędy. Te w formularzu, takie jak „Token CSRF jest nieprawidłowy. Spróbuj ponownie przesłać formularz”. a także dodatkowe błędy w podrzędnych formularzach, które nie mają propagacji błędów.

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = $this->getErrorMessages($child);
        }
    }

    return $errors;
}

Aby pobrać wszystkie błędy jako ciąg:

$string = var_export($this->getErrorMessages($form), true);

Symfony 2.5 / 3.0:

$string = (string) $form->getErrors(true, false);

Dokumenty:
https://github.com/symfony/symfony/blob/master/UPGRADE-2.5.md#form https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md#form (at spód: The method Form::getErrorsAsString() was removed)

Trzepnięcie
źródło
1
To wygląda na najbardziej poprawną odpowiedź dla obecnego Symfony 2.4.
Slava Fomin II
@Flip It Działa idealnie w dniu 2.5
iarroyo
1
Świetna odpowiedź, ALE zgłaszano$errors[$child->getName()] = $this->getErrorMessages($child); wyjątek, ponieważ w komponencie Symfony \ Bundle \ FrameworkBundle \ Controller \ Controller brakowało getErrorMessages . Więc zastąpiłem go$form_errors[$child->getName()] = $child->getErrorsAsString();
Ahad Ali
3
@AhadAli to funkcja rekurencyjna, więc kiedy umieścisz fragment kodu w klasie, w której potrzebujesz tej funkcji, będzie on mógł wywołać samą siebie. Twoja „poprawka” uniemożliwi dostęp do zagnieżdżonych formularzy. Zadziałało dla 37 innych osób, powinno też działać dla Ciebie;)
Flip
@Flip Ah, przepraszam, tylko patrzyłem $this->getErrorMessages()i pomyślałem, że jest wywoływany bezpośrednio w kontrolerze i części api Symfony.
Ahad Ali
47

Poniżej znajduje się rozwiązanie, które działało dla mnie. Ta funkcja znajduje się w kontrolerze i zwróci uporządkowaną tablicę wszystkich komunikatów o błędach i pola, które je spowodowało.

Symfony 2.0:

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

Symfony 2.1 i nowsze:

private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();

    if ($form->hasChildren()) {
        foreach ($form->getChildren() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }   
    }

    return $errors;
}
Icode4food
źródło
5
Ulepszony gist.github.com/2011671, ale nadal nie to, czego chcę. Chcę, aby klucze tablic były nazwami pól, ale tak nie jest.
umpirsky
9
W powyższym kodzie nie ma odniesienia do @SalmanPK Twig. Chyba nie rozumiem twojego komentarza.
Icode4food
1
Oto poprawka dla poprzedniej istoty, działa to pod Symfony 2.1.7. gist.github.com/WishCow/5101428
K. Norbert
Wygląda na to, $this->getFormErrorsże $this->getErrorMessagesw Twojej próbce w Symfony 2.1 powinna znajdować się literówka
Mick
@umpirsky Aby uzyskać nazwę pola, otrzymałem to: $ child-> getConfig () -> getOptions () ['label'] Zajęło mi wieczność, aby się dowiedzieć ...
jsgoupil
35

Użyj walidatora, aby pobrać błędy dla określonej encji

if( $form->isValid() )
{
    // ...
}
else
{
    // get a ConstraintViolationList
    $errors = $this->get('validator')->validate( $user );

    $result = '';

    // iterate on it
    foreach( $errors as $error )
    {
        // Do stuff with:
        //   $error->getPropertyPath() : the field that caused the error
        //   $error->getMessage() : the error message
    }
}

Dokumentacja API:

Olivier „Ölbaum” Scherler
źródło
Dzięki, potrzebowałem +1
Phill Pafford
4
Nie jestem pewien, czy sprawdzanie poprawności każdej jednostki osobno jest dobrym podejściem. A co jeśli masz złożoną formę hierarchiczną? Drugi problem polega na tym, że walidacja odbywa się dwukrotnie.
Slava Fomin II
3
@SlavaFominII - „Drugi problem polega na tym, że walidacja odbywa się dwukrotnie” - Słuszna uwaga, nic nie jest odświeżane! Ta sama lista błędów po!
BentCoder,
20

Aby uzyskać prawidłowe (możliwe do przetłumaczenia) wiadomości, obecnie używające SF 2.6.3, oto moja ostatnia funkcja (ponieważ żadna z powyższych nie wydaje się już działać):

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, false) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->current()->getMessage());
        $errors[] = $error->current()->getMessage();
    }

    return $errors;
}

ponieważ metoda Form :: getErrors () zwraca teraz wystąpienie FormErrorIterator , chyba że zmienisz drugi argument ($ flatten) na true . (Następnie zwróci instancję FormError i będziesz musiał bezpośrednio wywołać metodę getMessage (), bez metody current ():

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, true) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->getMessage());
        $errors[] = $error->getMessage();
    }

    return $errors;
}

)

Najważniejsze jest, aby ustawić pierwszy argument na wartość true, aby uzyskać błędy. Pozostawienie drugiego argumentu ($ flatten) na jego domyślną wartość ( true ) zwróci instancje FormError , natomiast przy ustawieniu wartości false zwróci instancje FormErrorIterator .

Cedo
źródło
Niezły, używając tych samych rzeczy.
Uszkodzone organiczne
prawda? :) @KidBinary
Cedo
Absolutnie cudowna kolego
:)
Lepszą opcją jest: $ errors = array_map (function ($ item) {return $ item-> current () -> getMessage ();}, $ campaignForm-> getErrors (true, false));
Enrique Quero
Dobre rozwiązanie dla Symfony 2.7
Yann Chabot
16

W przypadku moich wiadomości błyskawicznych byłem zadowolony $form->getErrorsAsString()

Edycja (z Benji_X80): Do użytku z SF3 $form->getErrors(true, false);

Tjorriemorrie
źródło
3
Wiem, że to stara odpowiedź, ale na przyszłość: This method should only be used to help debug a form.( źródło )
cheesemacfly
getErrorsAsString () jest przestarzała w 3.0, użyj: $ form-> getErrors (true, false);
Benji_X80
15

Funkcja dla symfony 2.1 i nowszych, bez żadnej przestarzałej funkcji:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return array
 */
private function getErrorMessages(\Symfony\Component\Form\Form $form)
{
    $errors = array();

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            /**
             * @var \Symfony\Component\Form\Form $child
             */
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        /**
         * @var \Symfony\Component\Form\FormError $error
         */
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }
    }

    return $errors;
}
stwe
źródło
Miałem zamieścić nową odpowiedź na ten post, ale wydawało się, że pokonałeś mnie na pięści. Musiałem przejrzeć kod źródłowy, aby dowiedzieć się, dlaczego nie znaleziono wywołań metod.
Dr Knowitall
Zauważyłem, że to nie przyciąga błędów z elementów, dla których propagacja błędów jest ustawiona na wartość true. SF2.4
kinghfb
@stwe, jaki jest cel pierwszego IFstwierdzenia? Dlaczego wyklucza się wzajemnie? O ile się orientuję: forma może mieć swoje własne błędy, jak i dzieci.
Slava Fomin II
4

Przetłumaczone komunikaty o błędach w formularzu (Symfony2.1)

Bardzo ciężko mi było znaleźć te informacje, więc myślę, że zdecydowanie warto dodać uwagę na temat tłumaczenia błędów formularza.

@Icode4foododpowiedź zwróci wszystkie błędy formularza. Jednak zwracana tablica nie uwzględnia ani liczby mnogiej, ani tłumaczenia komunikatu .

Możesz zmodyfikować pętlę foreach @Icode4foododpowiedzi, aby uzyskać kombinację:

  • Pobierz wszystkie błędy określonego formularza
  • Zwróć przetłumaczony błąd
  • W razie potrzeby weź pod uwagę liczbę mnogą

Oto ona:

foreach ($form->getErrors() as $key => $error) {

   //If the message requires pluralization
    if($error->getMessagePluralization() !== null) {
        $errors[] = $this->container->get('translator')->transChoice(
            $error->getMessage(), 
            $error->getMessagePluralization(), 
            $error->getMessageParameters(), 
            'validators'
            );
    } 
    //Otherwise, we do a classic translation
    else {
        $errors[] = $this->container->get('translator')->trans(
            $error->getMessage(), 
            array(), 
            'validators'
            );
    }
}

Ta odpowiedź została zebrana z 3 różnych postów:

Mick
źródło
Właśnie wypróbowałem twoją wersję i poszło Fatal Error: Call to undefined method Symfony\Component\Form\FormError::getMessagePluralization(). Podejrzewam, że to dotyczy tylko Symfony 2.1?
Czar Pino
4

SYMFONY 3.X

Inne podane tutaj metody SF 3.X nie zadziałały, ponieważ mogłem przesłać puste dane do formularza (ale mam ograniczenia NotNull / NotBlanck). W tym przypadku ciąg błędu wyglądałby następująco:

string(282) "ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be null.
name:
    ERROR: This value should not be blank.
"

Co nie jest zbyt przydatne. Więc zrobiłem to:

public function buildErrorArray(FormInterface $form)
{
    $errors = [];

    foreach ($form->all() as $child) {
        $errors = array_merge(
            $errors,
            $this->buildErrorArray($child)
        );
    }

    foreach ($form->getErrors() as $error) {
        $errors[$error->getCause()->getPropertyPath()] = $error->getMessage();
    }

    return $errors;
}

Który zwróciłby to:

array(7) {
  ["data.name"]=>
  string(31) "This value should not be blank."
  ["data.street"]=>
  string(31) "This value should not be blank."
  ["data.zipCode"]=>
  string(31) "This value should not be blank."
  ["data.city"]=>
  string(31) "This value should not be blank."
  ["data.state"]=>
  string(31) "This value should not be blank."
  ["data.countryCode"]=>
  string(31) "This value should not be blank."
  ["data.organization"]=>
  string(30) "This value should not be null."
}
sbouba
źródło
3

Możesz również skorzystać z usługi walidatora, aby uzyskać informacje o naruszeniach ograniczeń:

$errors = $this->get('validator')->validate($user);
antoinet
źródło
6
Spowoduje to walidację obiektu, ale nie formularza. Jeśli na przykład token CRSF był przyczyną błędu, komunikat nie zostałby uwzględniony.
Icode4food
3

Przetłumaczone komunikaty o błędach (Symfony2.3)

Moja wersja rozwiązania problemu:

/src/Acme/MyBundle/Resources/config/services.yml

services:
    form_errors:
        class: Acme\MyBundle\Form\FormErrors

/src/Acme/MyBundle/Form/FormErrors.php

<?php
namespace Acme\MyBundle\Form;

class FormErrors
{
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form);
    }

    private function getErrors($form)
    {
        $errors = array();

        if ($form instanceof \Symfony\Component\Form\Form) {

            // соберем ошибки элемента
            foreach ($form->getErrors() as $error) {

                $errors[] = $error->getMessage();
            }

            // пробежимся под дочерним элементам
            foreach ($form->all() as $key => $child) {
                /** @var $child \Symfony\Component\Form\Form */
                if ($err = $this->getErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

/src/Acme/MyBundle/Controller/DefaultController.php

$form = $this->createFormBuilder($entity)->getForm();
$form_errors = $this->get('form_errors')->getArray($form);
return new JsonResponse($form_errors);

W Symfony 2.5 możesz bardzo łatwo uzyskać wszystkie błędy pól:

    $errors = array();
    foreach ($form as $fieldName => $formField) {
        foreach ($formField->getErrors(true) as $error) {
            $errors[$fieldName] = $error->getMessage();
        }
    }
Lebnik
źródło
3

W przypadku Symfony 3.2 i nowszych użyj tego,

public function buildErrorArray(FormInterface $form)
{
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = (string) $child->getErrors(true, false);
        }
    }
    return $errors;
}

Użyj str_replace, jeśli chcesz pozbyć się irytującego tekstu „ Error: ” w każdym tekście opisu błędu.

$errors[$child->getName()] = str_replace('ERROR:', '', (string) $child->getErrors(true, false));
Anjana Silva
źródło
2

Jeśli używasz niestandardowych walidatorów, Symfony nie zwraca błędów generowanych przez te walidatory w plikach $form->getErrors(). $form->getErrorsAsString()zwróci wszystkie potrzebne błędy, ale jego wynik jest niestety sformatowany jako ciąg, a nie tablica.

Metoda, której używasz, aby uzyskać wszystkie błędy (niezależnie od tego, skąd pochodzą), zależy od używanej wersji Symfony.

Większość sugerowanych rozwiązań polega na utworzeniu funkcji rekurencyjnej, która skanuje wszystkie formularze podrzędne i wyodrębnia odpowiednie błędy do jednej tablicy. Symfony 2.3 nie ma tej $form->hasChildren()funkcji, ale ją posiada $form->all().

Oto klasa pomocnicza dla Symfony 2.3, której możesz użyć do wyodrębnienia wszystkich błędów z dowolnego formularza. (Jest oparty na kodzie z komentarza yapro do powiązanego zgłoszenia błędu na koncie github Symfony).

namespace MyApp\FormBundle\Helpers;

use Symfony\Component\Form\Form;

class FormErrorHelper
{
    /**
     * Work-around for bug where Symfony (2.3) does not return errors from custom validaters,
     * when you call $form->getErrors().
     * Based on code submitted in a comment here by yapro:
     * https://github.com/symfony/symfony/issues/7205
     *
     * @param Form $form
     * @return array Associative array of all errors
     */
    public function getFormErrors($form)
    {
        $errors = array();

        if ($form instanceof Form) {
            foreach ($form->getErrors() as $error) {
                $errors[] = $error->getMessage();
            }

            foreach ($form->all() as $key => $child) {
                /** @var $child Form */
                if ($err = $this->getFormErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

Kod telefoniczny:

namespace MyApp\ABCBundle\Controller;

use MyApp\FormBundle\Helpers;

class MyController extends Controller
{
    public function XYZAction()
    {
        // Create form.

        if (!$form->isValid()) {
            $formErrorHelper = new FormErrorHelper();
            $formErrors = $formErrorHelper->getFormErrors($form);

            // Set error array into twig template here.
        }
    }

}
Jay Sheth
źródło
2

Na podstawie odpowiedzi @Jay Seth stworzyłem wersję klasy FormErrors specjalnie dla Ajax Forms:

// src/AppBundle/Form/FormErrors.php
namespace AppBundle\Form;

class FormErrors
{

    /**
     * @param \Symfony\Component\Form\Form $form
     *
     * @return array $errors
     */
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form, $form->getName());
    }

    /**
     * @param \Symfony\Component\Form\Form $baseForm
     * @param \Symfony\Component\Form\Form $baseFormName
     *
     * @return array $errors
     */
    private function getErrors($baseForm, $baseFormName) {
        $errors = array();
        if ($baseForm instanceof \Symfony\Component\Form\Form) {
            foreach($baseForm->getErrors() as $error) {
                $errors[] = array(
                    "mess"      => $error->getMessage(),
                    "key"       => $baseFormName
                );
            }

            foreach ($baseForm->all() as $key => $child) {
                if(($child instanceof \Symfony\Component\Form\Form)) {
                    $cErrors = $this->getErrors($child, $baseFormName . "_" . $child->getName());
                    $errors = array_merge($errors, $cErrors);
                }
            }
        }
        return $errors;
    }
}

Użycie (np. W Twojej akcji):

$errors = $this->get('form_errors')->getArray($form);

Wersja Symfony: 2.8.4

Przykładowa odpowiedź JSON:

{
    "success": false,
    "errors": [{
        "mess": "error_message",
        "key": "RegistrationForm_user_firstname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_lastname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_email"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_zipCode"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_password_password"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_marketing"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_marketing"
    }]
}

Obiekt błędu zawiera pole „klucz”, które jest identyfikatorem wejściowego elementu DOM, dzięki czemu można łatwo wypełnić komunikaty o błędach.

Jeśli masz formularze podrzędne wewnątrz rodzica, nie zapomnij dodać cascade_validationopcji wewnątrz formularza nadrzędnego setDefaults.

Bandyta
źródło
1

W Symfony 2.1 i późniejszych do użytku z wyświetlaniem błędów Twig zmieniłem funkcję, aby dodać FormError zamiast po prostu je pobierać, dzięki czemu masz większą kontrolę nad błędami i nie musisz używać error_bubbling na każdym pojedynczym wejściu. Jeśli nie ustawisz go w poniższy sposób, {{form_errors (form)}} pozostanie puste:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return void
 */
private function setErrorMessages(\Symfony\Component\Form\Form $form) {      

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                if( isset($this->getErrorMessages($child)[0]) ) {
                    $error = new FormError( $this->getErrorMessages($child)[0] );
                    $form->addError($error);
                }
            }
        }
    }

}
Hard-Boiled Wonderland
źródło
1

$ form-> getErrors () działa dla mnie.

ahyong
źródło
1

Wymyśliłem takie rozwiązanie. Działa solidnie z najnowszą wersją Symfony 2.4 .

Spróbuję udzielić kilku wyjaśnień.

Korzystanie z oddzielnego walidatora

Myślę, że to zły pomysł, aby używać oddzielnej walidacji do walidacji jednostek i zwracania komunikatów o naruszeniu ograniczeń, jak sugerowali inni autorzy.

  1. Będziesz musiał ręcznie zweryfikować wszystkie jednostki, określić grupy walidacyjne itp. W przypadku złożonych form hierarchicznych jest to w ogóle niepraktyczne i szybko wymknie się spod kontroli.

  2. W ten sposób będziesz walidować formularz dwukrotnie: raz z formularzem i raz z oddzielnym walidatorem. To zły pomysł z punktu widzenia wydajności.

Proponuję rekurencyjnie iterować typ formularza z jego dziećmi, aby zbierać komunikaty o błędach.

Korzystanie z niektórych sugerowanych metod z wyłączną instrukcją IF

Niektóre odpowiedzi sugerowane przez innych autorów zawierają wzajemnie wykluczające się stwierdzenia IF, takie jak: if ($form->count() > 0)lub if ($form->hasChildren()).

O ile wiem, każdy formularz może zawierać błędy, a także dzieci. Nie jestem ekspertem w komponentach Symfony Forms , ale w praktyce nie dostaniesz błędów samego formularza, takich jak błąd ochrony CSRF lub błąd dodatkowych pól . Proponuję usunąć tę separację.

Korzystanie ze zdenormalizowanej struktury wyników

Niektórzy autorzy sugerują umieszczenie wszystkich błędów w zwykłej tablicy. Zatem wszystkie komunikaty o błędach samego formularza i jego elementów potomnych zostaną dodane do tej samej tablicy z różnymi strategiami indeksowania: na podstawie liczb dla własnych błędów typu i na podstawie nazw dla błędów podrzędnych. Proponuję użyć znormalizowanej struktury danych w postaci:

errors:
    - "Self error"
    - "Another self error"

children
    - "some_child":
        errors:
            - "Children error"
            - "Another children error"

        children
            - "deeper_child":
                errors:
                    - "Children error"
                    - "Another children error"

    - "another_child":
        errors:
            - "Children error"
            - "Another children error"

W ten sposób wynik można łatwo powtórzyć później.

Moje rozwiązanie

Oto moje rozwiązanie tego problemu:

use Symfony\Component\Form\Form;

/**
 * @param Form $form
 * @return array
 */
protected function getFormErrors(Form $form)
{
    $result = [];

    // No need for further processing if form is valid.
    if ($form->isValid()) {
        return $result;
    }

    // Looking for own errors.
    $errors = $form->getErrors();
    if (count($errors)) {
        $result['errors'] = [];
        foreach ($errors as $error) {
            $result['errors'][] = $error->getMessage();
        }
    }

    // Looking for invalid children and collecting errors recursively.
    if ($form->count()) {
        $childErrors = [];
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                $childErrors[$child->getName()] = $this->getFormErrors($child);
            }
        }
        if (count($childErrors)) {
            $result['children'] = $childErrors;
        }
    }

    return $result;
}

Mam nadzieję, że to komuś pomoże.

Slava Fomin II
źródło
@weaverryan, czy możesz rzucić okiem na moje rozwiązanie? Czy jest to poprawne, czy są jakieś wady lub nieporozumienia? Dziękuję Ci!
Slava Fomin II
1

SYMFONY 3.1

Po prostu zaimplementowałem statyczną metodę obsługi wyświetlania błędów

static function serializeFormErrors(Form\Form $form)
{
    $errors = array();
    /**
     * @var  $key
     * @var Form\Form $child
     */
    foreach ($form->all() as $key => $child) {
        if (!$child->isValid()) {
            foreach ($child->getErrors() as $error) {
                $errors[$key] = $error->getMessage();
            }
        }
    }

    return $errors;
}

Mam nadzieję, że pomogę

Shigiang Liu
źródło
1

Symfony 3 i nowsze

Niedawno stworzyłem funkcję, która tworzy drzewo błędów formularza. Będzie to pomocne przy zwracaniu listy błędów z powrotem do front-endu. Opiera się to na typach formularzy, które mają:

'error_bubbling' => false

Kod:

public static function getFormErrorsTree(FormInterface $form): array
{
    $errors = [];

    if (count($form->getErrors()) > 0) {
        foreach ($form->getErrors() as $error) {
            $errors[] = $error->getMessage();
        }
    } else {
        foreach ($form->all() as $child) {
            $childTree = self::getFormErrorsTree($child);

            if (count($childTree) > 0) {
                $errors[$child->getName()] = $childTree;
            }
        }
    }

    return $errors;
}

Wynik:

Array
(
    [name] => Array
        (
            [0] => This value is not valid.
        )

    [emails] => Array
        (
            [0] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )
            [1] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )

        )

)

Uwaga : Wiem, że błędy z pól z głębszych poziomów mogą zostać nadpisane, jeśli wyższy poziom zawiera błędy, ale jest to celowe dla mojego użytku.

Krzysztof Trzos
źródło
Idealne dla var_dump, dzięki
ReaperSoon
0

Dla Symfony 2.1:

Oto moje ostateczne rozwiązanie łączące wiele innych rozwiązań:

protected function getAllFormErrorMessages($form)
{
    $retval = array();
    foreach ($form->getErrors() as $key => $error) {
        if($error->getMessagePluralization() !== null) {
            $retval['message'] = $this->get('translator')->transChoice(
                $error->getMessage(), 
                $error->getMessagePluralization(), 
                $error->getMessageParameters(), 
                'validators'
            );
        } else {
            $retval['message'] = $this->get('translator')->trans($error->getMessage(), array(), 'validators');
        }
    }
    foreach ($form->all() as $name => $child) {
        $errors = $this->getAllFormErrorMessages($child);
        if (!empty($errors)) {
           $retval[$name] = $errors; 
        }
    }
    return $retval;
}
Fernando PG
źródło