Symfony2: So erhalten Sie Fehler bei der Formularüberprüfung, nachdem Sie die Anforderung an das Formular gebunden haben

110

Hier ist mein saveActionCode (an den das Formular die Daten weiterleitet)

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

Meine Frage ist: Wie bekomme ich die Fehler, wenn ich $form->isValid()zurückkomme false?

putolaruan
quelle

Antworten:

117

Sie haben zwei Möglichkeiten:

  • Leiten Sie den Benutzer bei einem Fehler nicht um und zeigen Sie ihn {{ form_errors(form) }}in der Vorlagendatei an
  • Zugriffsfehler-Array als $form->getErrors()
nefo_x
quelle
22
Ich habe das zweite gemacht, was Sie vorgeschlagen haben, aber form-> getErrors () gibt ein leeres Array zurück.
Putolaruan
2
Ich habe auch den ersten gemacht (mit PHP-Vorlagen <? Php echo $ view ['form'] -> Fehler ($ form)?>), Aber es ist immer noch leer!
Putolaruan
59
@mives Sie müssen error_bubblingin Ihrem Formulartyp auf true setzen , indem Sie die Option für jedes einzelne Feld explizit festlegen .
kgilden
5
Wenn Sie benutzerdefinierte Validatoren verwenden, gibt Symfony keine Fehler zurück, die von diesen Validatoren in $ form-> getErrors () generiert wurden.
Jay Sheth
13
Sie können auch $form->getErrors(true)Fehler von untergeordneten Formularen einschließen
Chris
103

Symfony 2.3 / 2.4:

Diese Funktion enthält alle Fehler. Diejenigen auf dem Formular wie "Das CSRF-Token ist ungültig. Bitte versuchen Sie, das Formular erneut einzureichen." sowie zusätzliche Fehler in den Formularkindern, bei denen kein Fehler auftritt.

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

So erhalten Sie alle Fehler als Zeichenfolge:

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

Symfony 2.5 / 3.0:

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

Dokumente:
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 unten: The method Form::getErrorsAsString() was removed)

Flip
quelle
1
Dies scheint die richtigste Antwort für das aktuelle Symfony 2.4 zu sein.
Slava Fomin II
@ Flip es funktioniert perfekt auf 2.5
iarroyo
1
Gute Antwort, ABER es $errors[$child->getName()] = $this->getErrorMessages($child);wurde eine Ausnahme ausgelöst , da getErrorMessages in der Symfony \ Bundle \ FrameworkBundle \ Controller \ Controller- Komponente fehlte . Also habe ich es ersetzt durch$form_errors[$child->getName()] = $child->getErrorsAsString();
Ahad Ali
3
@AhadAli ist eine rekursive Funktion. Wenn Sie also das Code-Snippet in die Klasse einfügen, in der Sie diese Funktionalität benötigen, kann es sich selbst aufrufen. Ihr "Fix" verhindert, dass Sie die verschachtelten Formulare erreichen. Es hat für 37 andere Leute funktioniert, es sollte auch für Sie funktionieren;)
Flip
@Flip Ah sorry mein schlechtes, ich habe nur geschaut $this->getErrorMessages()und ich dachte, es wird direkt in einem Controller und einem Teil der Symfony-API aufgerufen.
Ahad Ali
47

Unten ist die Lösung, die für mich funktioniert hat. Diese Funktion befindet sich in einer Steuerung und gibt ein strukturiertes Array aller Fehlermeldungen und des Feldes zurück, das sie verursacht hat.

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 und neuer:

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
quelle
5
Verbessertes gist.github.com/2011671, aber immer noch nicht das, was ich will. Ich möchte, dass Array-Schlüssel Feldnamen sind, aber das sind sie nicht.
Umpirsky
9
@SalmanPK Twig wird im obigen Code nirgends referenziert. Ich glaube nicht, dass ich Ihren Kommentar verstehe.
Icode4food
1
Hier ist ein Fix für den vorherigen Kern, der unter Symfony 2.1.7 funktioniert. gist.github.com/WishCow/5101428
K. Norbert
Es sieht aus wie ein Tippfehler $this->getFormErrorssollte $this->getErrorMessagesin Symfony2.1 in Ihrem Probe
Mick
@umpirsky Um den Feldnamen zu erhalten, habe ich Folgendes erhalten: $ child-> getConfig () -> getOptions () ['label'] Ich habe ewig
gebraucht
35

Verwenden Sie den Validator, um die Fehler für eine bestimmte Entität abzurufen

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

API-Referenz:

Olivier 'Ölbaum' Scherler
quelle
Danke, was ich brauchte +1
Phill Pafford
4
Ich bin mir nicht sicher, ob es ein guter Ansatz ist, jede Entität einzeln zu validieren. Was ist, wenn Sie eine komplexe hierarchische Form haben? Das zweite Problem ist, dass die Validierung zweimal erfolgt.
Slava Fomin II
3
@SlavaFominII - "Das zweite Problem ist, dass die Validierung zweimal erfolgt" - Guter Punkt, nichts wird aktualisiert! Gleiche Fehlerliste nach!
BentCoder
20

Um korrekte (übersetzbare) Nachrichten zu erhalten, die derzeit SF 2.6.3 verwenden, ist hier meine letzte Funktion (da keine der oben genannten Funktionen mehr zu funktionieren scheint):

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

Die Form :: getErrors () -Methode gibt jetzt eine Instanz von FormErrorIterator zurück , es sei denn, Sie ändern das zweite Argument ($ flatten) auf true . (Es wird dann eine FormError- Instanz zurückgegeben, und Sie müssen die getMessage () -Methode direkt ohne die current () -Methode aufrufen:

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

)

Das Wichtigste ist, das erste Argument auf true zu setzen, um die Fehler zu erhalten. Wenn Sie das zweite Argument ($ flatten) auf seinem Standardwert ( true ) belassen , werden FormError- Instanzen zurückgegeben, während FormErrorIterator- Instanzen zurückgegeben werden, wenn false festgelegt wird.

Cedo
quelle
Schön, mit dem gleichen Zeug.
Beschädigte Bio
ist es nicht? :) @KidBinary
Cedo
Absolut wunderschön, Kumpel
Damaged Organic
Bessere Option ist: $ Errors = Array_Map (Funktion ($ Item) {Rückgabe $ Item-> Current () -> GetMessage ();}, $ CampaignForm-> GetErrors (True, False));
Enrique Quero
Gute Lösung für Symfony 2.7
Yann Chabot
16

Für meine Flash-Nachrichten war ich zufrieden $form->getErrorsAsString()

Bearbeiten (von Benji_X80): Für SF3 verwenden $form->getErrors(true, false);

Tjorriemorrie
quelle
3
Ich weiß, dass es eine alte Antwort ist, aber als zukünftige Referenz: This method should only be used to help debug a form.( Quelle )
Cheesemacfly
getErrorsAsString () ist in 3.0 veraltet. Verwenden Sie: $ form-> getErrors (true, false);
Benji_X80
15

Die Funktion für Symfony 2.1 und neuer, ohne veraltete Funktion:

/**
 * @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
quelle
Ich wollte eine neue Antwort auf diesen Beitrag veröffentlichen, aber Sie schienen mich bis zum Anschlag geschlagen zu haben. Ich musste den Quellcode durchsehen, um herauszufinden, warum die Methodenaufrufe nicht gefunden wurden.
Dr. Knowitall
Ich habe festgestellt, dass dies keine Fehler von Elementen hervorruft, bei denen das Sprudeln auf "true" gesetzt ist. SF2.4
kinghfb
@stwe was ist der Zweck der ersten IFAussage? Warum schließt es sich gegenseitig aus? Soweit ich sehen kann: Form kann sowohl eigene Fehler als auch Kinder haben.
Slava Fomin II
4

Übersetzte Formularfehlermeldungen (Symfony2.1)

Ich habe viel Mühe gehabt, diese Informationen zu finden, daher denke ich, dass es sich definitiv lohnt, einen Hinweis zur Übersetzung von Formularfehlern hinzuzufügen.

@Icode4foodDie Antwort gibt alle Fehler eines Formulars zurück. Das zurückgegebene Array berücksichtigt jedoch weder die Nachrichtenpluralisierung noch die Übersetzung .

Sie können die foreach- @Icode4foodAntwortschleife so ändern , dass eine Kombination angezeigt wird:

  • Holen Sie sich alle Fehler eines bestimmten Formulars
  • Gibt einen übersetzten Fehler zurück
  • Berücksichtigen Sie gegebenenfalls die Pluralisierung

Hier ist es:

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

Diese Antwort wurde aus 3 verschiedenen Beiträgen zusammengestellt:

Mick
quelle
Habe gerade deine Version ausprobiert und es ging Fatal Error: Call to undefined method Symfony\Component\Form\FormError::getMessagePluralization(). Ich vermute, dass dies nur für Symfony 2.1 ist?
Zar Pino
4

SYMFONY 3.X.

Andere hier angegebene SF 3.X-Methoden haben bei mir nicht funktioniert, da ich leere Daten an das Formular senden konnte (aber ich habe NotNull / NotBlanck-Einschränkungen). In diesem Fall würde die Fehlerzeichenfolge folgendermaßen aussehen:

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.
"

Welches ist nicht sehr nützlich. Also habe ich folgendes gemacht:

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

Welches würde das zurückgeben:

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
quelle
3

Sie können auch den Validator-Service verwenden, um Verstöße gegen Einschränkungen zu erhalten:

$errors = $this->get('validator')->validate($user);
Antoinet
quelle
6
Dadurch wird das Objekt überprüft, nicht jedoch das Formular. Wenn beispielsweise das CRSF-Token die Fehlerursache war, wurde die Nachricht nicht aufgenommen.
Icode4food
3

Übersetzte Formularfehlermeldungen (Symfony2.3)

Meine Version zur Lösung des Problems:

/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);

In Symfony 2.5 können Sie alle Feldfehler sehr einfach erhalten:

    $errors = array();
    foreach ($form as $fieldName => $formField) {
        foreach ($formField->getErrors(true) as $error) {
            $errors[$fieldName] = $error->getMessage();
        }
    }
Lebnik
quelle
3

Verwenden Sie für Symfony 3.2 und höher Folgendes :

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

Verwenden Sie str_replace, wenn Sie den lästigen Text " Fehler: " in jedem Fehlerbeschreibungstext entfernen möchten .

$errors[$child->getName()] = str_replace('ERROR:', '', (string) $child->getErrors(true, false));
Anjana Silva
quelle
2

Wenn Sie benutzerdefinierte Validatoren verwenden, gibt Symfony keine Fehler zurück, die von diesen Validatoren in generiert wurden $form->getErrors(). $form->getErrorsAsString()gibt alle Fehler zurück, die Sie benötigen, aber die Ausgabe ist leider als Zeichenfolge und nicht als Array formatiert.

Die Methode, mit der Sie alle Fehler abrufen (unabhängig davon, woher sie stammen), hängt davon ab, welche Version von Symfony Sie verwenden.

Die meisten der vorgeschlagenen Lösungen umfassen das Erstellen einer rekursiven Funktion, die alle untergeordneten Formulare scannt und die relevanten Fehler in ein Array extrahiert. Symfony 2.3 hat die $form->hasChildren()Funktion nicht, aber es hat$form->all() .

Hier ist eine Hilfsklasse für Symfony 2.3, mit der Sie alle Fehler aus jedem Formular extrahieren können. (Es basiert auf Code aus einem Kommentar von yapro zu einem verwandten Bug-Ticket in Symfony's Github-Account.)

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

Aufrufcode:

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
quelle
2

Basierend auf der Antwort von @Jay Seth habe ich eine Version der FormErrors-Klasse speziell für Ajax Forms erstellt:

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

Verwendung (zB in Ihrer Aktion):

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

Symfony-Version: 2.8.4

Beispiel für eine JSON-Antwort:

{
    "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"
    }]
}

Das Fehlerobjekt enthält das Feld "Schlüssel", das die ID des Eingabe-DOM-Elements ist, sodass Sie problemlos Fehlermeldungen ausfüllen können.

Wenn Sie untergeordnete Formulare im übergeordneten Formular haben, vergessen Sie nicht, die cascade_validationOption im übergeordneten Formular hinzuzufügen setDefaults.

Räuber
quelle
1

Ab Symfony 2.1 für die Verwendung mit der Twig-Fehleranzeige habe ich die Funktion geändert, um einen FormError hinzuzufügen, anstatt sie einfach abzurufen. Auf diese Weise haben Sie mehr Kontrolle über Fehler und müssen nicht error_bubbling für jede einzelne Eingabe verwenden. Wenn Sie es nicht wie folgt einstellen, bleibt {{form_errors (form)}} leer:

/**
 * @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);
                }
            }
        }
    }

}
Hart gekochtes Wunderland
quelle
1

$ form-> getErrors () funktioniert bei mir.

Ahyong
quelle
1

Ich habe diese Lösung gefunden. Es funktioniert solide mit dem neuesten Symfony 2.4 .

Ich werde versuchen, einige Erklärungen zu geben.

Separaten Validator verwenden

Ich denke, es ist eine schlechte Idee, eine separate Validierung zu verwenden, um Entitäten zu validieren und Nachrichten über Einschränkungsverletzungen zurückzugeben, wie von anderen Autoren vorgeschlagen.

  1. Sie müssen alle Entitäten manuell validieren, Validierungsgruppen angeben usw. usw. Bei komplexen hierarchischen Formularen ist dies überhaupt nicht praktikabel und gerät schnell außer Kontrolle.

  2. Auf diese Weise validieren Sie das Formular zweimal: einmal mit Formular und einmal mit separatem Validator. Dies ist aus Sicht der Leistung eine schlechte Idee.

Ich schlage vor, den Formulartyp mit seinen untergeordneten Elementen rekursiv zu iterieren, um Fehlermeldungen zu sammeln.

Verwendung einiger vorgeschlagener Methoden mit exklusiver IF-Anweisung

Einige von anderen Autoren vorgeschlagene Antworten enthalten sich gegenseitig ausschließende IF-Anweisungen wie diese: if ($form->count() > 0)oder if ($form->hasChildren()).

Soweit ich sehen kann, kann jedes Formular sowohl Fehler als auch Kinder enthalten. Ich bin kein Experte für Symfony Forms- Komponenten, aber in der Praxis werden einige Fehler des Formulars selbst nicht angezeigt , z. B. CSRF-Schutzfehler oder zusätzliche Felder . Ich schlage vor, diese Trennung zu entfernen.

Denormalisierte Ergebnisstruktur verwenden

Einige Autoren schlagen vor, alle Fehler in ein einfaches Array einzufügen. Daher werden alle Fehlermeldungen des Formulars selbst und seiner untergeordneten Elemente mit unterschiedlichen Indizierungsstrategien zum selben Array hinzugefügt: nummerbasiert für typeneigene Fehler und namenbasiert für untergeordnete Fehler. Ich schlage vor, eine normalisierte Datenstruktur des Formulars zu verwenden:

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"

Auf diese Weise kann das Ergebnis später leicht wiederholt werden.

Meine Lösung

Hier ist meine Lösung für dieses Problem:

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

Ich hoffe es wird jemandem helfen.

Slava Fomin II
quelle
@weaverryan Kannst du dir bitte meine Lösung ansehen? Ist es gültig oder gibt es Nachteile oder Missverständnisse? Danke dir!
Slava Fomin II
1

SYMFONY 3.1

Ich habe einfach eine statische Methode implementiert, um die Anzeige von Fehlern zu behandeln

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

Ich hoffe zu helfen

Shigiang Liu
quelle
1

Symfony 3 und neuer

Ich habe kürzlich eine Funktion erstellt, die einen Baum von Formularfehlern erstellt. Dies ist hilfreich, um die Liste der Fehler an das Front-End zurückzugeben. Dies basiert auf Formulartypen mit:

'error_bubbling' => false

Code:

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

Ausgabe:

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.
                )

        )

)

Hinweis : Ich weiß, dass Fehler aus Feldern auf tieferen Ebenen überschrieben werden können, wenn auf höheren Ebenen Fehler auftreten. Dies ist jedoch für meine Verwendung beabsichtigt.

Krzysztof Trzos
quelle
Perfekt für var_dump, danke
ReaperSoon
0

Für Symfony 2.1:

Dies ist meine endgültige Lösung, die viele andere Lösungen zusammenfasst:

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
quelle