Symfony2-验证不适用于嵌入式表单类型

我有一个结合了两个实体(用户和配置文件)的表单。

验证似乎工作在表单的第一部分,该部分来自用户实体,是表单的基础。

ProfileType 包含在 UserType 中。表单正确地呈现并显示正确的信息,因此它似乎正确地连接到 Profile 实体。只是在 ProfileType 上破坏了验证。

知道为什么一部分会有效,而另一部分不会吗?

密码如下:

确认

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()));
50589 次浏览

你也必须在你的 ProfiletType中加入 validation_groups。如果存在,则根据每种表单类型的 data_class分别进行验证。

根据 表单类型文档还可以使用 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

你是在使用 YML 还是注释?

我尝试在父窗体类上应用 cascade_validation选项,但仍然没有进行验证。在阅读了一些文档之后,我转到 app/config/config.yml,发现 framework->validation下的 enable_annotations被设置为 没错。显然,如果这是真的,验证服务将不再读取任何 validation.yml 文件。所以我把它改成了 假的现在表单正在验证。

我花了很长时间搜索,发现它正在将 '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 验证。

来自我的控制器:

$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))中的第四个参数

属于 Symfony 2.3

使用嵌入式表单和验证组可能会非常痛苦: Annote@Assert Valid ()不适合我(没有组也可以)。在 DefaultOptions 上插入‘ cade _ valid’= > 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
));
}


//(...)

希望能有所帮助。

我也在找同样的东西,这就是我找到的

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上测试过,它很好用。

对于使用 Symfony 3.0或更高版本的用户,请注意: cascade_validation选项 已经被移除了:

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

很抱歉在这个旧帖子上添加了一个稍微偏离主题的答案(Symfony 3 vs. 2) ,但是在这里找到这些信息可以为我节省几个小时的时间。