75

2つのエンティティ(ユーザーとプロファイル)を組み合わせたフォームがあります。

検証は、ユーザーエンティティから送信され、フォームの基礎となるフォームの最初の部分で機能するようです。

ProfileTypeはUserType内に含まれています。フォームは正しくレンダリングされ、正しい情報が表示されるため、プロファイルエンティティに適切に接続されているようです。ProfileTypeで壊れているのは検証だけです。

なぜ一方の部分が検証され、もう一方の部分が検証されないのかについてのアイデアはありますか?

以下のコード:

Validation.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';
    }
}

コントローラ

$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()));
4

8 に答える 8

117

私は検索に時間を費やし、それがそれを修正した私の親型のクラス'cascade_validation' => trueの配列に追加されていることを発見しました(スレッドですでに述べたように)。setDefaults()これにより、フォームに表示されている子タイプでエンティティ制約の検証がトリガーされます。例えば

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

コレクションの場合は、フォームのコレクションフィールドの配列にも必ず追加'cascade_validation' => trueしてください。$options例えば

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

これにより、コレクションで使用される子エンティティで行われるべきであるように、UniqueEntityの検証が行われます。

于 2013-06-21T14:29:14.410 に答える
81

Symfony 3.0以降を使用している方への注意:cascade_validationオプションは削除されました。代わりに、埋め込みフォームには以下を使用してください。

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

この古いスレッドに少しオフトピックの回答(Symfony 3対2)を追加して申し訳ありませんが、ここでこの情報を見つけることで、今日は数時間を節約できたでしょう。

于 2016-06-14T13:17:51.870 に答える
36

フォームタイプのドキュメントによると、オプションValidの代わりに制約を使用することもできcascade_validationます。

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

所有者エンティティからの例:

/**
 * @var Collection
 *
 * @ORM\OneToMany(targetEntity="Child", ...)
 * @Assert\Valid()
 */
private $children
于 2012-12-20T14:19:27.450 に答える
4

私はまったく同じものを探していました、そしてここに私が見つけたものがあります

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

次のように、メインエンティティにサブエンティティを検証するように指示する必要があります。

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

私はこれをsymfony2.8でテストしましたが、動作します。

于 2015-12-16T14:13:37.327 に答える
3

YMLまたはアノテーションを使用していますか?

親フォームクラスにオプションを適用しようとしましたcascade_validationが、検証がまだ行われませんでした。少しのドキュメントを読んだ後、私はに行って、 underがtrueに設定されapp/config/config.ymlていることを発見しました。明らかに、これが当てはまる場合、検証サービスは、validation.ymlファイルを読み取りません。だから私はそれをfalseに変更しました、そして今フォームはうまく検証されています。enable_annotationsframework->validation

于 2013-04-09T18:34:54.923 に答える
3

Symfony2.3に属します

埋め込まれたフォームと検証グループを操作するのは非常に面倒な場合があります。アノテーション@Assert\Valid()は私には機能しません(グループがなければ問題ありません)。DefaultOptionsに'cascade_validation'=>trueを挿入することが重要です。-> add()でこれを繰り返す必要はありません。注意:HTML5検証は検証グループと一緒には機能しません。

例:

2つのアドレスのコレクション。両方とも1:1単方向。それぞれに異なる(!)検証グループがあります。

  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;

//(...)
}

アドレスエンティティ

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;

アドレスタイプ-検証グループを変更する機能

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

そして最後に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
    ));
}

//(...)    

それが役に立てば幸い..

于 2014-11-21T12:49:33.443 に答える
2

あなたもあなたを追加する必要がありvalidation_groupsますProfiletType。検証は、存在する場合に基づいて、各フォームタイプで個別に行われdata_classます。

于 2012-04-13T10:47:33.297 に答える
0

私のコントローラーから:

$form = $this->get('form.factory')
        ->createNamedBuilder('form_data', 'form', $item, array('cascade_validation' => true))
        ->add('data', new ItemDataType())
        ->add('assets', new ItemAssetsType($this->locale))
        ->add('contact', new ItemContactType())
        ->add('save', 'submit',
            array(
                'label' => 'Save',
                'attr' => array('class' => 'btn')
            )
        )
        ->getForm();

::createNamedBuilderの4番目のパラメータ-array('cascade_validation' => true))

于 2013-08-11T20:21:46.473 に答える