Symfony 2 仅在字段值存在时验证 [英] Symfony 2 validate only if field value present
问题描述
我在 Symfony2 中遇到验证系统问题.我有一个在注册和帐户更新时验证的帐户实体.该实体具有用户名、密码、姓名、电子邮件等.在帐户更新屏幕上,我允许更新帐户的用户名和密码.我希望只有在输入值时才更新帐户的密码,这可以很好地实现,但验证失败,因为验证器需要密码.如果我使用密码和没有密码的帐户创建单独的组进行注册,则根本不会对其进行验证.我希望它仅在输入新密码时进行验证.在这种情况下是否可以进行条件验证?
I am having a problem with the validation system in Symfony2. I have a Account entity which is validated on registration and account update. The entity has username, password, name, email etc. On the Account Update screen I allow to update on both the username and password for the account. I would like the password to be updated on the account only if a value is entered, which is implemented fine but the validation fails because the Validator expects a password there. If I make a separate group for registration with the password and account without the password it will not validate it at all. I want it to validate only if a new password is entered there. Is a conditional validation possible in this scenario?
推荐答案
将一些逻辑添加到您的验证表单过程中非常容易.您可以将可调用对象传递给 'validation_groups' OptionsResolverInterface.
To add some logic into your validation form process is very easy. You can pass an callable to 'validation_groups' OptionsResolverInterface.
示例(来自 Symfony2 书籍):
Example (from Symfony2 book):
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => function(FormInterface $form) {
$data = $form->getData();
if (Entity\Client::TYPE_PERSON == $data->getType()) {
return array('person');
} else {
return array('company');
}
},
));
}
或者:
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array(
'Acme\AcmeBundle\Entity\Client',
'determineValidationGroups',
),
));
}
查看:http://symfony.com/doc/current/book/forms.html#groups-based-on-the-submitted-data
编辑 1:
试试这个:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => function(FormInterface $form) {
$account = $form->getData();
$password = $account->getPassword();
if (!empty($password)) {
return array('group_with_password');
} else {
return array('group_without_password');
}
},
));
}
编辑 2:
您可以使用表单事件 Symfony2[1].事件 Symfony\Component\Form\FormEvents::PRE_SUBMIT 在设置用户对象之前为您提供数组上的数据.
You could use the form events Symfony2[1]. The event Symfony\Component\Form\FormEvents::PRE_SUBMIT give you the data on an array before being set on the user object.
一个好的方法是使用另一个属性(未映射到数据库)来存储用户输入的密码.像这样:
A good approach is use another attribute (not mapped to database), to store the password typed by the user. Like this:
<?php
/**
* @ORM\Entity
* @ORM\Table(name="user")
*/
class User {
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* The password encrypted.
* @var string
*
* @ORM\Column(type="text", nullable=true)
*/
protected $password;
/**
* Password in plain text. This field should not be mapped as Doctrine field.
*
* @var string
*/
protected $plainPasword;
}
$plainPassword 用于用户可以设置/更改其密码的表单.此属性始终为空,除非用户更改密码.
The $plainPassword is used in forms that user can set/change their password. This attribute always will be null, except when the users change their passwords.
$password 用于存储 $plainPassword 的加密版本.此属性将存储在数据库中.
The $password is used to store the encrypted version of $plainPassword. This attribute will be stored in database.
要知道何时给出新密码,只需检查控制器/服务中的 $plainPassword.查看示例住所:
To know when a new password is given, simply check $plainPassword in your controller/service. Check out the example abode:
/**
*
* @Route("user/{id}", name="user_update")
* @Method("POST")
* @Template()
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('MyBundle:User')->find($id);
if (!$user) {
throw $this->createNotFoundException('Unable to find User entity.');
}
$editForm = $this->createEditForm($user);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$user = $editForm->getData();
$newPassword = $user->getPlainPassword();
if (!empty($newPassword)) {
$encodeFactory = $this->get('security.encoder_factory');
$passwordEncoder = $factory->getEncoder($user);
$encodedPassword = $encoder->encodePassword($newPassword, $user->getSalt());
$user->setPassword($encodedPassword);
}
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('user_show', array('id' => $id)));
}
return array(
'entity' => $user,
'edit_form' => $editForm->createView(),
);
}
简而言之,我将所有逻辑都放在控制器中,但最好将它们移到服务中.这是FOSUserBundle do[2][3]的方式.
To be short and didactic, I put all the logic in controller, but is better move them to a service. This is the way of FOSUserBundle do[2][3].
[1] http://symfony.com/doc/current/components/form/form_events.html
[2] https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php
[3] https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php
这篇关于Symfony 2 仅在字段值存在时验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!