I use the FOS User bundle and LdapBundle for my users to connect to the website.
I created a form, and I want to keep a track on who added an entry. So I want to save to the database the user that added/modified that thing.
What is the best way to do this ? Since it's going to be a form, my first thought was to create an hidden field on my FormType with the current user id, but I think it's safe.
Any suggestion would be appreciated.
Thanks !
I dont know ldapBundle but when i want to save for example a photo i do in my controller
$user=$this->security_context->getToken()->getUser();
$form = $this->createForm(new PhotoType(), $photo )
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$photo->setUser($user);
$em = $this->getDoctrine()->getManager();
$em->persist($photo);
$em->flush();
....
Its a basic code, you also have to check if the user exist beofre doing the persistance : if($user) ...
I would suggest against the hidden field as it could be easily manipulated.
The better way would be to inject SecurityContext into your form and bind the logged in user to that object via POST_SUBMIT event.
Related
I am implementing a logical erase for my Symfony 3 entities.
On my entities, I added a $deleted field, and I created some delete-controllers with this code:
$entity->setDeleted(true);
$em->persist($entity);
$em->flush();
Then, I modified also my queries to avoid select 'deleted' entities. And works great.
The problem:
I have some entities with Unique Constraint (for example, email field on user table), so when I delete an user, and then try to add the same user with the same email, symfony shows a validation form error due to 'duplicated email'.
I tried to control this on controller in the following way:
$user = new User();
$em = $this->getDoctrine()->getManager();
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
//Check for deleted duplication:
$duplicatedUser = $em->getRepository('AppBundle:User')
->getDuplicatedAndDeletedUser($user);
if($duplicatedUser != null){
$em->remove($duplicatedUser);
$em->flush();
}
if ($form->isValid()) {
$em->persist($user);
$em->flush();
}
}
But this code doesn't avoid the form validation error. First time when I try to create, Stymfony shows an error, and then, if I resubmit the form, it works because of the duplicated entity was removed from db.
How can I solve this issue?
Note: I know this: http://atlantic18.github.io/DoctrineExtensions/doc/softdeleteable.html but, I have already developed all the logic described, so I prefer go in my way with this.
Finally I find the sollution.
As you can see here http://symfony.com/doc/current/forms.html#handling-form-submissions handleRequest() method validate the form, so delete the entity after that don't solve the problem at all.
I do that to get form data:
$userName = $request->request->get('user')['email'];
And then check if this $userName is already used. If so, I delete the user before handleRequest() call.
Hope this help others.
Something strange in your code, I can see a user getting created but it doesn't get injected in the form so it can be used to store data in it and I also don't see the form anywhere, was it created in the controller or is it pure html, if so, you would need to fill in the user with the data from the form with $formName->getData() function or if you so wish, fill in only individual fields with the $formName['fieldname']->getData(). Try this code:
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$em = $this->getDoctrine()->getManager();
//Check for deleted duplication:
$duplicatedUser = $em->getRepository('AppBundle:User')
->getDuplicatedAndDeletedUser($user);
if($duplicatedUser != null){
$em->remove($duplicatedUser);
$em->flush();
}
$em->persist($user);
$em->flush();
}
i'm trying to do a simple add without the form generated by doctrine
$mail = new Subscription();
$request = $this->getRequest();
if ($request->getMethod() == "POST") {
$em = $this->getDoctrine()->getManager();
$samplees = $request->get("samplees");
$mail->setEmail($samplees);
$em->persist($mail);
$em->flush();
return $this->redirect($this->generateUrl('user_homepage'));
}
First of all, Doctrine2 will not handle any form facility (nor creation neither data binding process): the whole process is up to symfony and its form bundle.
That said, if you need to retrieve a posted data you need to modify
$samplees = $request->get("samplees");
into
$samplees = $request->request->get("samplees");
This because $request is the whole Request object (so, basically, it will handle also get parameters [$request->query->get(...)] just to say one of the functionalities)
I've tried searching about updating data in Symfony2 but look like all tutorials need few normal steps to do this :
Manager initialisation $em = $this->getDoctrine()->getManager();
Make Entity with criteria $entity =
$em->getRepository('bundle')->find($id);
Create Form $form = $this->createForm(new Type(), $entity);
Bind with request $editForm->handleRequest($request);
Flush data $em->flush();
Let say that I have custom form in twig and do manual getRequest in controller $variable = $request->request->get('name');. Is there any way I can do to update this data for specific ID in entity $entity = $em->getRepository('bundle')->find($id); without create a form for flush my data?
Because I need to update this variable for many ID in my database using iteration. Let say that I have thousands data need to updated with this value. I'm worried if creating form will impact to performance and time.
Simply set your data directly in your entity using your setters and then flush:
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('Bundle:Entity')->find($id);
$entity->setSomeProperty($propertyValue);
$em->flush();
I am using FOSUserBundle and I am trying to create a page that allows a user to update their user profile. The problem I am facing is that my form does not require that the user reenter their password if they don't want to change/update their password. So when a user submits the form with an empty password the database will be updated with an empty string, and the user will not be able to log in.
How can I get my form to ignore updating the password field if it is not set? Below is the code I am using.
$user = $this->get('security.context')->getToken()->getUser();
//user form has email and repeating password fields
$userForm = $this->createForm(new UserFormType(), $user);
if ($request->getMethod() == 'POST') {
$userForm->bindRequest($request);
if($userForm->isValid()){
//this will be be empty string in the database if the user does not enter a password
$user->setPlainPassword($userForm->getData()->getPassword());
$em->flush();
}
}
I have tried a few things such as the following, but this is still empty because the bindRequest sets the empty password to the user
if($userForm->getData()->getPassword())
$user->setPlainPassword($userForm->getData()->getPassword());
I have also tried, but this results in a similar situation and causes an unneeded query
if($userForm->getData()->getPassword())
$user->setPlainPassword($userForm->getData()->getPassword());
else
$user->setPlainPassword($user->getPlainPassword());
Are there any elegant ways to handle this use case?
The problem is that you bind a form to a User Object before controls upon password.
Let's analyze your snippet of code.
Do the following
$user = $this->get('security.context')->getToken()->getUser();
will load an existing user into a User Object. Now you "build" a form with that data and if receive a post, you'll take the posted data into the previous object
$userForm = $this->createForm(new UserFormType(), $user);
if ($request->getMethod() == 'POST') {
$userForm->bindRequest($request);
So, onto bindRequest you have alredy lost previous password into the object (obviously not into database yet) if that was leave empty. Every control from now on is useless.
A solution in that case is to manually verify value of form's field directly into $request object before binding it to the underlying object.
You can do this with this simple snippet of code
$postedValues = $request->request->get('formName');
Now you have to verify that password value is filled
if($postedValues['plainPassword']) { ... }
where plainPassword I suppose to be the name of the field we're interesting in.
If you find that this field contain a value (else branch) you haven't to do anything.
Otherwise you have to retrieve original password from User Object and set it into $request corrisponding value.
(update) Otherwise you may retrieve password from User Object but since that password is stored with an hased valued, you can't put it into the $request object because it will suffer from hashing again.
What you could do - i suppose - is an array_pop directly into $request object and put away the field that messes all the things up (plainPassword)
Now that you had done those things, you can bind posted data to underlying object.
Another solution (maybe better because you move some business logic away from controller) is to use prePersist hook, but is more conceptually advanced. If you want to explore that solution, you can read this about form events
I think you should reconsider if this is in fact a good use case. Should users be able to edit other users passwords? At our institution we do not allow even the highest level admin to perform this task.
If a user needs their password changed we let them handle that themselves. If they have forgotten their password we allow them to retrieve it via email. If they need assistance with adjusting their email we allow our admins to assist users then. But all password updating and creation is done soley by the user.
I think it is great that FOSUserBundle makes it so difficult to do otherwise but if you must DonCallisto seems to have a good solution.
<?php
class User
{
public function setPassword($password)
{
if (false == empty($password)) {
$this->password = $password;
}
}
}
This will only update the password on the user if it isn't empty.
I have found a simple hack to get rid of the "Enter a password" form error.
Manualy set a dummy plainPassword in the user entity. After form validation just reset it before you flush the entity.
<?php
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AppBundle:User')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Customer entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$postedValues = $request->request->get('appbundle_user');
/* HERE */ $entity->setPlainPassword('dummy'); // hack to avoid the "enter password" error
$editForm->handleRequest($request);
if ($editForm->isValid()) {
/* AND HERE */ $entity->setPlainPassword(''); // hack to avoid the "enter password" error
$em->flush();
return $this->redirect($this->generateUrl('customer_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
I want to create a confirmation window when I fill in a form.
Right now, I fill in the form and if the form is valid, the entity is persisted and returned a view with my entity as a parameter. But this isn't what I want.
If the form is valid I don't want to persist the entity. If it's valid, would have to show a view using my parameter(entity) and then if my user clicks the button to confirm, persist the entity and redirect to other view. If my user clicks the button to return, I use the JavaScript function: javascript:history.back(1).
How I can do this?
An easy way is to store your bound entity in session (a flash) and retrieve it after confirmation for persistence.
In your "saveForm" action:
if ($form->isValid()) {
$myEntity = $form->getData();
$this->get('session')->setFlash('my_entity', $myEntity);
return $this->render('MyBundle:Controller:confirmation.html.twig', array(
'entity' => $myEntity
));
}
And in your "confirmSave" action:
$myEntity = $this->get('session')->getFlash('my_entity');
$this->em->persist($myEntity);
$this->em->flush();
It's just a basic example an it needs to be adaped to your project.