我有一个结合了两个实体(用户和配置文件)的表单。
验证似乎适用于表单的第一部分,该部分来自用户实体,并且是表单的基础。
配置文件类型包含在用户类型中。窗体正确呈现并显示正确的信息,因此它似乎已正确连接到配置文件实体。这只是在配置文件类型上中断的验证。
知道为什么一部分会验证而另一部分不会吗?
代码如下:
验证.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: ~
用户类型.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';
}
}
配置文件类型.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,
));
这将在集合中使用的子实体中进行唯一实体验证。
给那些使用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
我正在寻找完全相同的东西,这是我发现的
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上对此进行了测试,并且可以工作。
你使用的是YML还是注释?
我尝试在父窗体类上应用 cascade_validation
选项,但仍然没有进行验证。在阅读了一些文档后,我去了app/config/config.yml
,发现framework->validation
下的enable_annotations
设置为true。显然,如果这是真的,验证服务没有孤独者读取任何 validation.yml 文件。所以我只是将其更改为 false,现在表单验证正常。
属于Symfony 2.3
使用嵌入式表单和验证组可能会非常痛苦:注释 @Assert''Valid() 对我不起作用(没有组没关系)。在默认选项上插入 'cascade_validation' => true 是键。你不需要在 ->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,
));
}
(...)
最后是集合类型
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
));
}
//(...)
希望对您有所帮助。
还必须在ProfiletType
中添加validation_groups
。验证根据其data_class
(如果存在)在每种表单类型中单独完成。
从我的控制器:
$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))