Symfony2 – проверка не работает для встроенного типа формы

У меня есть форма, объединяющая два объекта (User и Profile).

Валидация, похоже, работает над первой частью формы, которая формируется из пользовательской сущности и является основой формы.

Профиль TypeType включен внутри UserType. Форма корректно отображает и отображает правильную информацию, поэтому кажется, что она правильно подключена к объекту Profile. Это просто проверка, которая нарушена в профиле 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())); 

Я провел поиск по возрасту и обнаружил, что он добавлял '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, как и в дочернем объекте, используемом в коллекции.

Примечание для тех, кто использует Symfony 3.0 и выше: опция cascade_validation была удалена . Вместо этого используйте встроенные формы:

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

Извините за добавление в этот старый поток с небольшим ответом вне темы (Symfony 3 против 2), но найти эту информацию здесь бы спасли меня несколько часов сегодня.

В соответствии с документацией типа типа вы также можете использовать параметр 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 

Принадлежит Symfony 2.3

Работа со встроенными формами и группами проверки может быть довольно болезненной: Annotation @Assert \ Valid () не работает для меня (без групп это нормально). Вставьте ключ «cascade_validation» => true в DefaultOptions. Вам не нужно повторять это на -> add (). Будьте осторожны: проверка HTML 5 не работает вместе с группами проверки.

Пример:

Коллекция из 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 )); } //(...) 

Надеюсь, поможет..

Вы также должны добавить validation_groups в свой ProfiletType . Проверка выполняется в каждом виде формы отдельно на основе их data_class если существует.

вы используете YML или аннотации?

Я попытался применить параметр cascade_validation в своем классе родительской формы, но проверка еще не произошла. Прочитав небольшую документацию, я пошел в app/config/config.yml и обнаружил, что для enable_annotations в framework->validation установлено значение true . По-видимому, если это так, служба проверки не имеет права на чтение любых файлов validation.yml. Поэтому я просто изменил его на false , и теперь форма хорошо проверяется.

Я искал то же самое, и вот что я нашел

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

Вы должны сказать основному объекту, чтобы проверить его сущности следующим образом:

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

Я тестировал это на symfony 2.8, и он работает.

От моего контроллера:

 $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 – array('cascade_validation' => true))