2017-03-20 19 views
1

我有一個具有plainPassword和密碼屬性的實體。在形式上,我映射在plainPassword上。之後,當用戶驗證表單時,我在plainPassword上進行密碼驗證。堅持不變的字段變化實體

要對密碼進行編碼,我使用EventSubscriber來偵聽prePersist和preUpdate。它適用於註冊表格,因爲它是一個新的實體,用戶填充一些持久屬性,然後教義堅持它並刷新。

但是,當我只想編輯密碼時,它不起作用,我認爲這是因爲用戶只編輯了非持久屬性。然後主義不會試圖堅持它。但我需要它,輸入訂閱者。

有人知道該怎麼做嗎? (我在其他實體中遇到類似問題)目前,我在控制器中執行操作...

非常感謝。

我UserSubscriber

class UserSubscriber implements EventSubscriber 
    { 
     private $passwordEncoder; 
     private $tokenGenerator; 

     public function __construct(UserPasswordEncoder $passwordEncoder, TokenGenerator $tokenGenerator) 
     { 
      $this->passwordEncoder = $passwordEncoder; 
      $this->tokenGenerator = $tokenGenerator; 
     } 

     public function getSubscribedEvents() 
     { 
      return array(
       'prePersist', 
       'preUpdate', 
     ); 
     } 

     public function prePersist(LifecycleEventArgs $args) 
     { 
      $object = $args->getObject(); 
      if ($object instanceof User) { 
       $this->createActivationToken($object); 
       $this->encodePassword($object); 
      } 
     } 

     public function preUpdate(LifecycleEventArgs $args) 
     { 
      $object = $args->getObject(); 
      if ($object instanceof User) { 
       $this->encodePassword($object); 
      } 
     } 

     private function createActivationToken(User $user) 
     { 
      // If it's not a new object, return 
      if (null !== $user->getId()) { 
       return; 
      } 

      $token = $this->tokenGenerator->generateToken(); 
      $user->setConfirmationToken($token); 
     } 

     private function encodePassword(User $user) 
     { 
      if (null === $user->getPlainPassword()) { 
       return; 
      } 

      $encodedPassword = $this->passwordEncoder->encodePassword($user, $user->getPlainPassword()); 
      $user->setPassword($encodedPassword); 
     } 

我的用戶實體:

class User implements AdvancedUserInterface, \Serializable 
{ 
/** 
* @ORM\Id 
* @ORM\Column(type="integer") 
* @ORM\GeneratedValue(strategy="AUTO") 
*/ 
protected $id; 

/** 
* @ORM\Column(name="email", type="string", length=255, unique=true) 
* @Assert\NotBlank() 
* @Assert\Email() 
*/ 
private $email; 

/** 
* @Assert\Length(max=4096) 
*/ 
private $plainPassword; 

/** 
* @ORM\Column(name="password", type="string", length=64) 
*/ 

private $password; 

ProfileController可:

class ProfileController extends Controller 
{ 
/** 
* @Route("/my-profile/password/edit", name="user_password_edit") 
* @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')") 
*/ 
public function editPasswordAction(Request $request) 
{ 
    $user = $this->getUser(); 
    $form = $this->createForm(ChangePasswordType::class, $user); 
    $form->handleRequest($request); 
    if ($form->isSubmitted() && $form->isValid()) { 
     // Encode the password 
     // If I decomment it, it's work, but I want to do it autmaticlally, but in the form I just change the plainPassword, that is not persisted in database 
     //$password = $this->get('security.password_encoder')->encodePassword($user, $user->getPlainPassword()); 
     //$user->setPassword($password); 
     $em = $this->getDoctrine()->getManager(); 
     $em->flush(); 
     $this->addFlash('success', 'Your password have been successfully changed.'); 
     return $this->redirectToRoute('user_profile'); 
    } 
    return $this->render('user/password/edit.html.twig', [ 
     'form' => $form->createView(), 
    ]); 
} 

}

+0

你能顯示'實體'嗎? –

+0

是的,實體存在,我可以看到它,當我編輯密碼時,如果我做轉儲,我可以看到plainPassword集,但是不保留plainPassword,那麼我認爲doctrine什麼都不做......也許有一種可能性強制主義堅持? – mpiot

+0

這是正常的行爲,因爲您永遠不應該以純文本保存密碼。 –

回答

1

您可以強制主義來標記對象由MANIP髒直接使用UnitOfWork。

$em->getUnitOfWork()->scheduleForUpdate($entity) 

但是,我強烈不鼓勵這種方法,因爲它違反了精心設計的抽象層。

+0

Thx,那麼有什麼更好的辦法呢?你有好主意嗎 ? – mpiot

+1

@Sheppard如前所述[在我之前發送的鏈接中](https://github.com/FriendsOfSymfony/FOSUserBundle/issues/1487),使用'update(User $ user)'方法創建一個UserManager,並簡單地使用更新用戶的密碼。如果對象不是「髒」,則Doctrine的LifeCycleEvents不會觸發。 – Pete

+0

@Sheppard然而,如果你迫切想要它自動發生,這(明確標記對象髒)是唯一的方法。但是,調用'scheduleForUpdate()'也可以調用'updateUserPassword($ user)'。你不會贏得任何東西:/ – Pete