Avoid blank password field when editing specific user using SonataAdminBundle

I had a problem when I want to edit an existing user from Backend (using SonataAdminBundle and FOSUserBundle). In the configureFormFields method of my UserAdmin class, the password field is empty, and this is a problem when I need to edit other fields (for example, the last name) while keeping the same user password. This field (and password verification field) must be filled again! (I do not want to change the user password)

In my UserAdmin class, I have:

public function configureFormFields(FormMapper $formMapper) { $formMapper ->with('User Data') ->add('username') ->add('plainPassword', 'repeated', array( 'type' => 'password', 'options' => array('translation_domain' => 'FOSUserBundle'), 'first_options' => array('label' => 'form.password'), 'second_options' => array('label' => 'form.password_confirmation'), 'invalid_message' => 'fos_user.password.mismatch', )) ->add('firstname') ->add('lastname') ->add('email') ->add('user_roles') ->add('enabled', 'checkbox', array( 'label' => 'Enable Account', 'required' => false, )) ->end() ; } 

I tried to overwrite the prePersist and preUpdate methods in my UserAdmin class, but they do not work. The password is entered into the database according to the FOS standard (with salt and sha512).

Any solution? Thank you very much!

+6
source share
5 answers

You can override the preUpdate function in your admin class, so I did

 public function preUpdate($object) { $DM = $this->getConfigurationPool()->getContainer()->get('Doctrine')->getManager(); $repository = $DM->getRepository('Namespace\YourBundle\Entity\User')->find($object->getId()); $Password = $object->getPassword(); if (!empty($Password)) { $salt = md5(time()); $encoderservice = $this->getConfigurationPool()->getContainer()->get('security.encoder_factory'); $encoder = $encoderservice->getEncoder($object); $encoded_pass = $encoder->encodePassword($object->getPassword(), $salt); $object->setSalt($salt); $object->setPassword($encoded_pass); } else { $object->setPassword($repository->getPassword()); } } 

And my configureFormFields function

 protected function configureFormFields(FormMapper $formMapper) { $passwordoptions=array('type' => 'password','invalid_message' => 'The password fields must match.', 'options' => array('attr' => array('class' => 'password-field')),'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Confirm password'),'translation_domain' => 'FOSUserBundle' ); $this->record_id = $this->request->get($this->getIdParameter()); if (!empty($this->record_id)) { $passwordoptions['required'] = false; $passwordoptions['constraints'] = array(new Assert\Length(array('min' => 10)) ,new Assert\Regex(array('pattern' => '/^(?=.*?[AZ])(?=.*?[az])(?=.*?[0-9])(?=.*?[# ?!@ $%^&*-]).{10,}$/','match'=>true,'message'=>'Password must contain atleast 1 special character 1 upper case letter 1 number and 1 lower case letter !')) ); } else { $passwordoptions['required'] = true; $passwordoptions['constraints'] = array(new Assert\Length(array('min' => 10)) ,new Assert\Regex(array('pattern' => '/^(?=.*?[AZ])(?=.*?[az])(?=.*?[0-9])(?=.*?[# ?!@ $%^&*-]).{10,}$/','match'=>true,'message'=>'Password must contain atleast 1 special character 1 upper case letter 1 number and 1 lower case letter !')) ); } $formMapper->add('password', 'repeated', $passwordoptions); /*you can add your other fields*/ } 
+2
source

I have the same problem as yours, but without SonataAdminBundle .

In the classic admin management (Symfony3), this works:

 // src/AppBundle/Form/UserType.php <?php namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { // By default, password is required (create user case) $passwordOptions = array( 'type' => PasswordType::class, 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat password'), 'required' => true ); // If edit user : password is optional // User object is stored in $options['data'] $recordId = $options['data']->getId(); if (!empty($recordId)) { $passwordOptions['required'] = false; } $builder ->add('prenom', TextType::class, array('label' => 'First name')) ->add('nom', TextType::class, array('label' => 'Last name')) ->add('email', EmailType::class) ->add('username', TextType::class) ->add('plainPassword', RepeatedType::class, $passwordOptions) ->add('roleList', ChoiceType::class, array( 'label' => 'Role', 'choices' => array( 'Admin' => 'ROLE_ADMIN', 'User' => 'ROLE_USER' ), )) ->add('save', SubmitType::class, array( 'attr' => array('class' => 'button-link save'), 'label' => 'Validate' )); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\User', )); } } 

Remember to delete @Assert \ NotBlank () in plainPassword in your user:

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

My editAction () in UserController.php:

  /** * @Route("/users/edit/{id}", name="user_edit") */ public function editAction($id, Request $request) { // get user from database $em = $this->getDoctrine()->getManager(); $user = $em->getRepository('AppBundle:User')->find($id); // user doesn't exist if (!$user) { throw $this->createNotFoundException('No user found for id '. $id); } // build the form with user data $originalPassword = $user->getPassword(); # encoded password $form = $this->createForm(UserType::class, $user); // form POST $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { // Encode the password if needed # password has changed if (!empty($form->get('plainPassword')->getData())) { $password = $this->get('security.password_encoder') ->encodePassword($user, $user->getPlainPassword()); $user->setPassword($password); # password not changed } else { $user->setPassword($originalPassword); } $role = $form->get('roleList')->getData(); $user->setRoles(array($role)); // update the User $em->flush(); // success message $this->addFlash('notice', 'User has been updated successfully !'); // redirection return $this->redirectToRoute('user'); } // show form return $this->render('users/form.html.twig', array( 'h1_title' => 'Edit user : ' . $user->getPrenom() . " " . $user->getNom(), 'form' => $form->createView() )); } 

Now, when you create a new user, a password is required, but this is not when you edit it.

+2
source

Perhaps too late, but good for others. Thanks to other posts. So simple. Just use:

 class UserAdmin extends AbstractAdmin { protected $formOptions = array( 'validation_groups' => array('Profile') ); //.. } 

It uses the profile validation group defined in:

friendsofsymfony / custom package / Resources / configurations / validation.xml

+1
source

There are several ways to do this.

Change configureFormField behavior

You can get the current object ( $this->subject or $this->getSubject(); ) inside configureFormFields and check if it has a new object or an existing one and change the behavior of the fields (e.g. check)

Using saveHooks and FOSUser

here is an example

http://sonata-project.org/bundles/admin/master/doc/reference/saving_hooks.html

this will show the hashed password in the password field, but should update it when entering a new simple one (if I remember correctly)

Combine and implement your own logic

inside the hook you can get the FOSUserManager and handle the user update with

container: $this->getConfigurationPool()->getContainer();

fosusermanager: $userManager = $container->get('fos_user.user_manager');

https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/user_manager.md

0
source

I highly recommend that if you use the SonataAdminBundle in conjunction with the FOSUserBundle, you should also install the SonataUserBundle . This will fix your problem as it already copes with this problem and also comes with standard admin classes. Check the installation very easily to combine it with the FOSUserBundle. I know that a lot of additional fields are also added in the user object, but you can redefine the package if you want to have only your fields.

-1
source

All Articles