Symfony2 – Validierung funktioniert nicht für eingebetteten Formulartyp

Lesezeit: 8 Minuten

Benutzer-Avatar
Herr Pablo

Ich habe ein Formular, das zwei Entitäten (Benutzer und Profil) kombiniert.

Die Validierung scheint im ersten Teil des Formulars zu funktionieren, der von der Benutzerentität stammt und die Grundlage des Formulars bildet.

Der ProfileType ist im UserType enthalten. Das Formular wird korrekt gerendert und zeigt die richtigen Informationen an, sodass es scheint, dass es ordnungsgemäß mit der Profilentität verbunden ist. Es ist nur die Validierung, die für den ProfileType unterbrochen ist.

Irgendeine Idee, warum ein Teil validieren würde und der andere nicht?

Code unten:

Validierung.yml

DEMO\DemoBundle\Entity\User\Profile:
    properties:
        address1:
            - NotBlank: { groups: [profile] }
        name:
            - NotBlank: { groups: [profile] }
        companyName:
            - NotBlank: { groups: [profile] }

DEMO\DemoBundle\Entity\User\User:
    properties:
        username:
            - NotBlank:
                groups: profile
                message: Username cannot be left blank.
        email:
            - NotBlank:
                groups: profile
                message: Email cannot be left blank
            - Email:
                groups: profile
                message: The email "{{ value }}" is not a valid email.
                checkMX: true
        password:
            - MaxLength: { limit: 20, message: "Your password must not exceed {{ limit }} characters." }
            - MinLength: { limit: 4, message: "Your password must have at least {{ limit }} characters." }
            - NotBlank: ~

UserType.php

namespace DEMO\DemoBundle\Form\Type\User;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormError;

use DEMO\DemoBundle\Form\Type\User\ProfileType;

class UserType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('username');
        $builder->add('email');
        $builder->add('profile', new ProfileType());
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'DEMO\DemoBundle\Entity\User\User',
            'validation_groups' => array('profile')
        );
    }

    public function getName()
    {
        return 'user';
    }
}

ProfileType.php

namespace DEMO\DemoBundle\Form\Type\User;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormError;

class ProfileType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('name');
        $builder->add('companyName', null, array('label' => 'Company Name'));
        $builder->add('address1', null, array('label' => 'Address 1'));
        $builder->add('address2', null, array('label' => 'Address 2'));
        $builder->add('city');
        $builder->add('county');
        $builder->add('postcode');
        $builder->add('telephone');
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'DEMO\DemoBundle\Entity\User\Profile',
        );
    }

    public function getName()
    {
        return 'profile';
    }
}

Regler

$user = $this->get('security.context')->getToken()->getUser();

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

        if ($request->getMethod() == 'POST') {
            $form->bindRequest($request);

            if ($form->isValid()) {
                // Get $_POST data and submit to DB
                $em = $this->getDoctrine()->getEntityManager();
                $em->persist($user);
                $em->flush();

                // Set "success" flash notification
                $this->get('session')->setFlash('success', 'Profile saved.');
            }

        }

        return $this->render('DEMODemoBundle:User\Dashboard:profile.html.twig', array('form' => $form->createView()));

Benutzer-Avatar
daftv4der

Ich verbrachte eine Ewigkeit mit der Suche und stellte fest, dass es hinzufügte 'cascade_validation' => true zum setDefaults() array in der Klasse meines übergeordneten Typs, die es behoben hat (wie bereits im Thread erwähnt). Dadurch wird die Validierung der Entitätseinschränkung in den im Formular angezeigten untergeordneten Typen ausgelöst. z.B

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(            
        ...
        'cascade_validation' => true,
    ));
}

Achten Sie bei Sammlungen auch darauf, hinzuzufügen 'cascade_validation' => true zum $options Array für das Erfassungsfeld auf dem Formular. z.B

$builder->add('children', 'collection', array(
    'type'         => new ChildType(),
    'cascade_validation' => true,
));

Dadurch wird die UniqueEntity-Validierung so durchgeführt, wie sie in der in der Sammlung verwendeten untergeordneten Entität stattfinden sollte.

  • Wie haben Sie herausgefunden, dass Sie das Kaskaden-Flag zum Options-Array für die Sammlung hinzufügen mussten? Das war mein Problem, aber ich bin in Symfony-Dokumenten nicht darauf gestoßen?

    – redbirdo

    30. September 2013 um 10:44 Uhr

  • Durch das Durchsuchen vieler anderer Kommentare zu ähnlichen Themen hier :/

    – daftv4der

    13. Dezember 2013 um 10:40 Uhr

  • Einfacher können Sie eine „valid“-Einschränkung in der Datei „validation.yml“ angeben, um die Validierung für Objekte zu aktivieren, die als Eigenschaften eines zu validierenden Objekts eingebettet sind symfony.com/doc/current/reference/constraints/Valid.html

    – sdespont

    27. Januar 2015 um 16:15 Uhr


  • Für diejenigen, die Symfony 3.0 und höher verwenden: cascade_validation wurde entfernt. Siehe meine Antwort unten für Details.

    – vgl.

    14. Juni 2016 um 13:19 Uhr

  • @sdespont Wenn eine Entität eine andere erweitert, wo die Eigenschaft mit Assert\Valid() Anmerkung definiert ist, wird die erste Entität die Validierung für diese Eigenschaft nicht kaskadieren. So cascade_validation das Problem lösen.

    – paaacman

    19. März 2017 um 21:13 Uhr

Ein Hinweis für die Benutzer Symfony 3.0 und oben: die cascade_validation Möglichkeit wurde entfernt. Verwenden Sie stattdessen Folgendes für eingebettete Formulare:

$builder->add('embedded_data', CustomFormType::class, array(
    'constraints' => array(new Valid()),
));

Tut mir leid, dass ich diesen alten Thread mit einer leicht vom Thema abweichenden Antwort (Symfony 3 vs. 2) ergänzt habe, aber wenn ich diese Informationen hier gefunden hätte, hätte ich heute ein paar Stunden gespart.

  • super, danke. Die validierte Antwort sollte auch Ihre enthalten.

    – Ali

    1. September 2016 um 9:12 Uhr

  • Dies ist die einzige Option, die für mich in Symfony 3.1.4 funktioniert. Nach der Dokumentation symfony.com/doc/current/form/embedded.html und das Hinzufügen von @Assert\Valid() Constrait zu Entity, wie es geschrieben ist, funktioniert nicht. In meinem Fall verwende ich FOSUserBundle und eine benutzerdefinierte Benutzerentität, die sich auf UserProfile (OneToOne) bezieht. Danke @cg.

    – heilen85

    6. September 2016 um 12:24 Uhr


  • Damit möchten Sie vielleicht abschalten Fehler sprudelt.

    – Jorr.it

    16. April 2017 um 12:12 Uhr

  • Verdammt, habe einige Zeit damit verbracht, danach zu suchen …. was ist dann der Zweck von @Assert\Valid -.- … diese Art von Hacks sind eine echte Abkehr, jetzt müssen wir uns an zwei zusätzlichen Stellen um die Validierung kümmern. Vielen Dank @cg. !

    – Benjamin Vision

    30. Juni 2018 um 22:19 Uhr


  • Zusätzlich musste ich hinzufügen use Symfony\Component\Validator\Constraints\Valid; oben in der Formulardefinitionsdatei. Symfony 4 hier.

    – NullIstNicht0

    27. Juli 2018 um 7:06 Uhr

Benutzer-Avatar
Supernova

Entsprechend Formular Typ Dokumentation kannst du auch verwenden Valid Einschränkung statt cascade_validation Möglichkeit.

$builder->add('children', 'collection', array(
    'type'        => new ChildType(),
    'constraints' => array(new Valid()),
));

Beispiel aus der Eigentümereinheit:

/**
 * @var Collection
 *
 * @ORM\OneToMany(targetEntity="Child", ...)
 * @Assert\Valid()
 */
private $children

  • Und dazu gezwungen seit Symfony 3.0 (wie von @cg erwähnt)

    – Pierre de LESPINAY

    29. Juni 2016 um 14:52 Uhr


Ich habe genau das gleiche gesucht und hier ist, was ich gefunden habe

http://symfony.com/doc/master/book/forms.html#forms-embedding-single-object

Sie müssen der Hauptentität sagen, dass sie ihre Unterentitäten wie folgt validieren soll:

/**
 * @Assert\Type(type="AppBundle\Entity\Category")
 * @Assert\Valid()
 */
 private $subentity;

Ich habe dies auf Symfony 2.8 getestet und es funktioniert.

Verwenden Sie YML oder Anmerkungen?

Ich habe versucht, die anzuwenden cascade_validation Option in meiner übergeordneten Formularklasse, aber die Validierung fand immer noch nicht statt. Nachdem ich eine kleine Dokumentation gelesen hatte, ging ich zu app/config/config.yml und das gefunden enable_annotations unter framework->validation eingestellt war Stimmt. Wenn dies zutrifft, liest der Validierungsdienst anscheinend keine validation.yml-Dateien mehr. Also habe ich es einfach geändert FALSCHund jetzt wird das Formular gut validiert.

Benutzer-Avatar
Hauke

Gehört zu Symfony 2.3

Das Arbeiten mit eingebetteten Formularen und Validierungsgruppen kann ziemlich schmerzhaft sein: Annotation @Assert\Valid() funktioniert bei mir nicht (ohne Gruppen ist es ok). Fügen Sie ‘cascade_validation’ => true bei den DefaultOptions ein ist der Schlüssel. Sie müssen dies bei ->add() nicht wiederholen. Achtung: Die HTML 5-Validierung funktioniert nicht mit Validierungsgruppen.

Beispiel:

Eine Sammlung von 2 Adressen. Beides 1:1 unidirektional. Jeder mit einer anderen (!) Validierungsgruppe.

  class TestCollection{

//(...)

/**
 * @var string
 * @Assert\NotBlank(groups={"parentValGroup"})
 * @ORM\Column(name="name", type="string", length=255, nullable=true)
 */
protected $name;

/**
 * @var \Demo\Bundle\Entity\TestAddress  
 * @Assert\Type(type="Demo\Bundle\Entity\TestAddress")
 * @ORM\OneToOne(targetEntity="TestAddress",cascade={"persist","remove"},orphanRemoval=true)
 * @ORM\JoinColumn(name="billing_address__id", referencedColumnName="id")
 */
protected $billingAddress;

/**
 * @var \Demo\Bundle\Entity\TestAddress
 * @Assert\Type(type="Demo\Bundle\Entity\TestAddress")
 * @ORM\OneToOne(targetEntity="TestAddress",cascade={"persist","remove"}, orphanRemoval=true)
 * @ORM\JoinColumn(name="shipping_address__id", referencedColumnName="id")
 */ 
protected $shippingAddress;

//(...)
}

Adresseinheit

class TestAddress {
/**
 * @var string
 * @Assert\NotBlank(groups={"firstname"})
 * @ORM\Column(name="firstname", type="string", length=255, nullable=true)
 */
private $firstname;

/**
 * @var string
 * @Assert\NotBlank(groups={"lastname"})
 * @ORM\Column(name="lastname", type="string", length=255, nullable=true)
 */
private $lastname;

/**
 * @var string
 * @Assert\Email(groups={"firstname","lastname"}) 
 * @ORM\Column(name="email", type="string", length=255, nullable=true)
 */
private $email;

Adresstyp – Möglichkeit, die Validierungsgruppe zu ändern

class TestAddressType extends AbstractType {    
protected $validation_group=['lastname'];//switch group

public function __construct($validation_group=null) {
    if($validation_group!=null) $this->validation_group=$validation_group;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
    //disable html5 validation: it suchs with groups 

    $builder
        ->add('firstname',null,array('required'=>false))
        ->add('lastname',null,array('required'=>false))
        ->add('email',null,array('required'=>false))
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Demo\Bundle\Entity\TestAddress',           
        'validation_groups' => $this->validation_group,
    ));
}
(...)

Und zuletzt der CollectionType

class TestCollectionType extends AbstractType { 

public function buildForm(FormBuilderInterface $builder, array $options)
{   $builder
        ->add('name')           
        ->add('billingAddress', new TestAddressType(['lastname','firstname']))
        ->add('shippingAddress', new TestAddressType(['firstname']))            
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Demo\Bundle\Entity\TestCollection',
        'validation_groups' => array('parentValGroup'),         
        'cascade_validation' => true
    ));
}

//(...)    

Ich hoffe es hilft..

Benutzer-Avatar
Mun Mun Das

Sie müssen hinzufügen validation_groups in deiner ProfiletType Auch. Die Validierung erfolgt in jedem Formulartyp separat basierend auf deren data_class falls vorhanden.

  • Ich habe das nachträglich hinzugefügt, es hat nicht geholfen. Aber ich habe die Lösung gefunden. Ich musste ‘cascade_validation’ zum Options-Array hinzufügen. Verdammt ärgerlich, weil dies in den Symfony2-Dokumenten nirgendwo erwähnt wird.

    – Herr Pablo

    13. April 2012 um 10:54 Uhr

  • @MrPablo Ich nehme an, das ist der cascade_validation Option in 2.1?

    – Richsage

    3. Mai 2012 um 12:53 Uhr

  • @MrPablo Da Sie anscheinend eine Antwort auf Ihre Frage gefunden haben, ziehen Sie bitte in Betracht, Ihre eigene Antwort mit einem vollständigen Beispiel für die Verwendung von “cascade_validation” zu posten. Dies ist zu wichtig, um in einem Kommentar verbannt zu werden! Vielen Dank

    – Jean Valjean

    15. September 2012 um 14:34 Uhr

1345950cookie-checkSymfony2 – Validierung funktioniert nicht für eingebetteten Formulartyp

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy