我试图在表单中使用特定的验证器.
该表格是供用户重新定义他的密码,他还必须输入他当前的密码.
为此,我使用了symfony的内置验证器
在我的形式:
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
并且表单类型如下所示:
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('currentpassword', 'password', array('label'=>'Current password',
'mapped' => false,
'constraints' => new UserPassword(array('message' => 'you wot m8?')),
'required' => true
))
->add('password', 'repeated', array(
'first_name' => 'new',
'second_name' => 'confirm',
'type' => 'password',
'required' => true
))
;
}
我知道在我的控制器中我可以获取数据表单,获取currentpassword值,调用security.encoder_factory等,但验证器看起来很方便.
我的问题是表单总是返回错误(这里:’你输了m8?’)就像我输入了错误的当前密码一样.
知道我做错了什么吗?
解决方法:
我知道这个问题的答案会迟到几年,但是当我遇到同样的问题时,我想提出我的解决方案:
问题是我在用于FormMapping的$user实体和来自security.context的User之间存在连接.
请参阅以下内容:(PasswordChange – Controller)
$username = $this->getUser()->getUsername();
$user = $this->getDoctrine()->getRepository("BlueChordCmsBaseBundle:User")->findOneBy(array("username"=>$username));
// Equal to $user = $this->getUser();
$form = $this->createForm(new ChangePasswordType(), $user);
//ChangePasswordType equals the one 'thesearentthedroids' posted
$form->handleRequest($request);
if($request->getMethod() === "POST" && $form->isValid()) {
$manager = $this->getDoctrine()->getManager();
$user->setPassword(password_hash($user->getPassword(), PASSWORD_BCRYPT));
[...]
}
return array(...);
isValid()函数正在触发UserPassword Constraint Validator:
public function validate($password, Constraint $constraint)
{
if (!$constraint instanceof UserPassword) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword');
}
$user = $this->tokenStorage->getToken()->getUser();
if (!$user instanceof UserInterface) {
throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
}
$encoder = $this->encoderFactory->getEncoder($user);
if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
$this->context->addViolation($constraint->message);
}
}
感兴趣的行是:if(!$encoder-> isPasswordValid($user-> getPassword(),$password,$user-> getSalt()))
在我的情况下,$user-> getPassword()将我刚刚在表单中输入的新密码作为我的新密码.
这就是为什么测试总是失败!
我不明白为什么tokenStorage中的用户和我从数据库加载的用户之间可能存在连接.
感觉就像对象(MyDatabase one和tokenStorage)共享相同的处理器地址并且实际上是相同的……
奇怪的!
我的解决方案是将ChangePasswordType中的(新)密码字段与EntityMapping分离:参见
->add('currentpassword', 'password', array('label'=>'Current password', 'mapped' => false, 'constraints' => new UserPassword()))
->add('password', 'repeated', array(
'mapped' => false,
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
))
->add('Send', 'submit')
->add('Reset','reset')
感兴趣的线是’mapped’=>假,
这样,在表单中输入的新密码将不会自动映射到给定的$user实体.相反,你现在需要从表单中获取它.看到
$form->handleRequest($request);
if($request->getMethod() === "POST" && $form->isValid()) {
$data = $form->getData();
$manager = $this->getDoctrine()->getManager();
$user->setPassword(password_hash($data->getPassword(), PASSWORD_BCRYPT));
$manager->persist($user);
$manager->flush();
}
我无法完全理解问题的一些解决方法.如果有人可以解释数据库对象和security.context对象之间的连接,我很高兴听到它!