У меня есть форма, объединяющая два объекта (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))