Reputation: 55
I'm building a web application in Symfony 2 where I have a User entity class for holding registered users.
Every user should have at least a username and a password of course, hence, I use the @Assert\NotBlank
validation rule for both fields in the entity. The username is static, however, being able to change the password is desirable.
Thus, I'm building a form where signed in users can change their password (among other things). This form utilizes the repeated field type in Symfony for password confirmation purposes.
Now, in most cases I guess users are not looking to change their password, but rather update other fields in their profile. Therefore, I would want it to be possible for them to leave the password field blank. However, that will interfere with the NotBlank
validation rule.
Removing the NotBlank
validation rule is of course an option. Although, hardly the solution I'm looking for since that incures the problem of users ending up with a blank password.
Finally, As I understand it the symfony Request object autofills the form data back into the User entity on form submission.
Now, my question is: Is there any way to, upon empty password-field, make Symfony refill the User entity with the existing password from the database rather than a blank value? This would allow validation to follow through and won't cause any undesired changes to the password upon saving.
This is the code for the password field in the entity
/**
* @var string
*
* @ORM\Column(name="password",type="string",length=255)
* @Assert\NotBlank()
* @Assert\Type(type="string")
* @Assert\Length(max="255")
* @Assert\NotEqualTo(value="password")
*/
private $password;
This is the code for generating the form
private function initForm($user) {
return $this->createFormBuilder($user)
->add('name', 'text')
->add('mail', 'email')
->add('password', 'repeated', [
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'first_options' => ['label' => false],
'second_options' => ['label' => false] //set to false to hide label in view
])
->add('save', 'submit')->getForm();
}
This is the Action-code for the /profile/edit
page:
/**
* @ParamConverter("user",class="MyBundle:User")
*/
public function editAction(User $user, Request $request) {
$form = $this->initForm($user);
$form->handleRequest($request);
if ($form->isValid()) {
//update to database and redirect user back to profile_view
$this->getDoctrine()->getManager()->flush();
return $this->redirect($this->generateUrl('profile_view'));
}
return $this->render('MyBundle:User:edit.html.twig',
array('form' => $form->createView()));
}
Thanks in advance for any help!
I did try the "obvious" approach, i.e. temporarilly storing the original password in a variable and "putting" it back if it was blank after the form was submitted:
/**
* @ParamConverter("user",
class="MyBundle:User")
*/
public function editAction(User $user, Request $request) {
$password = $user->getPassword();
$form = $this->initForm($user)->getForm();
$form->handleRequest($request);
if ( $user->getPassword() == NULL ) {
$user->setPassword($password);
$form = $this->initForm($user)->getForm(); //this is the problem
}
if ( $form->isValid() ) {
//update to database and redirect user back to profile view
$this->getDoctrine()->getManager()->flush();
return $this->redirect($this->generateUrl('profile_view'));
}
return $this->render('MyBundle:User:edit.html.twig',
array('form' => $form->createView()));
}
However, this did not work for apparent reasons. When the form is reinitialised within the if
statement, Symfony finds the form has never been submitted in the first place, i.e. no validation is performed. And adding the $form->handleRequest($request)
leaves us back with the first problem where the password field might be blank.
What I do find peculiar though. Symfony validates the Entity and not the form. But removing the problem row $form->initForm($user)->getForm()
still didn't work, although the entity should be valid.
Upvotes: 0
Views: 1285
Reputation: 529
I think the solution reside with a EVENT
on the form it self.
Will keep your validation intact when creating a new user
Will put back the model data on the request data for a existing user with the password field empty
Will trigger validation for a existing user with a password field empty in the model data(DB)
->addEventListener(FormEvents::PRE_SUBMIT,function(FormEvent $event) {
/** @var array $requestData */
$requestData = $event->getData();
/** @var \AppBundle\Entity\User $user */
$user = $event->getForm()->getData();
if ($user && !$requestData['password']){
$requestData['password'] = $user->getPassword();
}
$event->setData($requestData);
})
The FormEvents::PRE_SUBMIT
will gave you access to 2 data type , who i commented with they respective type in the code.
$requestData
is the normalized data from the user input this data is going to be apply on the model in this case $user
, this will happen after the event PRE_SUBMIT
.
Validation will happen on the $requestData but only after PRE_SUBMIT
.
Upvotes: 1
Reputation: 3783
A solution is to use an extra class member $rawPassword
, not stored in database, to be only used on your form. You will, of course, have keep your $password
variable for database storage as defined in your question.
On your edit action, you just have to test after $form->bind($request);
if your user as a $rawPassword
password defined. If it's the case, update $password
with the encoding value of $rawPassword
, and flush.
EDIT : $form->bind($request);
below 2.3, $form->handleRequest($request);
otherwise.
Upvotes: 0