我已经建立了一个自定义的用户对象的UserType。 其中一个字段是一个密码。
理想情况下,我想它,当我提交表单的数据变压器/相关,而不必在控制器来处理这个编码的密码。 然而,这是一个腌密码,所以因为我喜欢我每次生成密码的时间来重新生成盐这就带来了问题。 我不知道的方式在我的DataTransformer获得这个额外的价值。
所以,我基本上有两个问题:
- 这是个好/坏主意,有它做编码的用户类型(AbstractType)的一部分,或者我应该处理它的控制器?
- 如何将所需的信息传递给我的DataTransformer,使这个可能吗?
谢谢。
所以,我做了一些挖掘和寻找,并采取了一些线索来自FOSUserBundle。
要回答我的第一个问题,看起来也不是最好的选择,从而使第二个问题毫无意义。
最后我做什么:
- 一个新的领域,添加到我的用户实体,
$plainPassword
。 然后,我改变了我的用户类型的映射到这个领域,而不是$的密码直接。 - 一定要空出
$plainPassword
在User::eraseCredentials
- 制定了一个名为的UserManager新的服务。 在此,我给它一个函数
updateUser()
负责处理密码的实际编码(不再控制器进行处理,耶!)。
这或多或少是什么FOSUserBundle一样。 然后,他们手动调用UpdateUser两个(我从Controller相信)。 不过,我希望能够了解这个步骤大部分给忘了。 这就是学说事件进来玩。
我加了两个学说事件侦听器(两者的UserManager):prePersist和更新前。
这两个基本检查,如果我们面对的是一个User对象,然后调用updateUser()
来更新用户的密码。 更新前不得不手动设置新值的额外步骤。
为了确保它触发, User::setPlainPassword()
抹了密码,并刷新我的盐(因为plainPassword不是对应的属性,所以只是改变它不会允许用户触发更新前的这是必要的)。
很多移动件,但现在,我有它在的地方,每当我使用User::setPlainPassword()
来更改密码的明文(无论在哪里),它现在会正确的编码和保存实际的密码值。 活泉!
namespace My\Bundle\UserBundle\DependencyInjection;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Event\LifecycleEventArgs;
use My\Bundle\UserBundle\Entity\User;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
class UserManager
{
protected $encoderFactory;
public function __construct(EncoderFactoryInterface $encoderFactory)
{
$this->encoderFactory = $encoderFactory;
}
public function getEncoder(User $user)
{
return $this->encoderFactory->getEncoder($user);
}
public function updateUser(User $user)
{
$plainPassword = $user->getPlainPassword();
if (!empty($plainPassword)) {
$encoder = $this->getEncoder($user);
$user->setPassword($encoder->encodePassword($plainPassword, $user->getSalt()));
$user->eraseCredentials();
}
}
public function preUpdate(PreUpdateEventArgs $event)
{
$user = $event->getEntity();
if (!($user instanceof \GamePlan\Bundle\UserBundle\Entity\User)) {
return;
}
$this->updateUser($user);
$event->setNewValue('password', $user->getPassword());
//die($event->getOldValue('password') . ' ' . $event->getNewValue('password') . ' ' . $event->hasChangedField('password') ? 'Y' : 'N');
}
public function prePersist(LifecycleEventArgs $event)
{
$user = $event->getEntity();
if (!($user instanceof \GamePlan\Bundle\UserBundle\Entity\User)) {
return;
}
$this->updateUser($user);
}
}
// In My\Bundle\UserBundle\Entity\User
public function setPlainPassword($plainPassword)
{
$this->plainPassword = $plainPassword;
// Change some mapped values so preUpdate will get called.
$this->refreshSalt(); // generates a new salt and sets it
$this->password = ''; // just blank it out
}
# In My/Bundle/UserBundle/Resources/config/services.yml
services:
my_user.manager:
class: My\Bundle\UserBundle\DependencyInjection\UserManager
arguments:
- @security.encoder_factory
tags:
- { name: doctrine.event_listener, event: prePersist }
- { name: doctrine.event_listener, event: preUpdate }