I am trying to add a simple form to allow my users to edit their profile. My problem is:
Since the entity \"linked\" to the form is the same as the current user obje
I used the same solution as FOSUserBundle, which is calling $em->refresh()
on my entity when the form validation fails:
public function profileAction()
{
$em = $this->getDoctrine()->getEntityManager();
$user = $this->get('security.context')->getToken()->getUser();
$entity = $em->getRepository('AcmeSecurityBundle:User')->find($user->id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find User entity.');
}
$form = $this->createForm(new ProfileType(), $entity);
$request = $this->getRequest();
if ($request->getMethod() === 'POST')
{
$form->bindRequest($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('profile'));
}
$em->refresh($user); // Add this line
}
return $this->render('AcmeSecurityBundle:User:profile.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
Note that if you are using what is called a "virtual" field in "How to handle File Uploads with Doctrine" (in my case "picture_file" you will need to clear it by hand:
$em->refresh($user);
$user->picture_file = null; // here
One approach would be to always redirect:
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('profile'));
Of course you lose error messages and changes.
Another approach would be to define an entity manager just for your UserProvider. $user
would no longer be the same as $entity
. Bit of extra overhead but it certainly makes the problem go and would prevent similar interactions with other forms that might modify all or part of an user entity.
In a similar fashion, you reduce the overhead by creating an entity manager just for your profile form. With this method, the overhead would only be incurred when editing the profile.
Finally, you could ask yourself if it really mattered that the display data was not quite right in this particular case. Would it really bother anything? Would anyone notice but you?
See How to work with Multiple Entity Managers in Symfony Cookbook
Another idea is to clone your user entity in your user provider. This will divorce it from the entity manager.
You could also use $entityManager->detach($user);
to remove the user from the entity manager.
And why is the token user an entity anyways? Consider making a completely independent User class with minimal information pulled from the database by your user provider. That is what I do.