Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid empty password field when edit a specific user with SonataAdminBundle

I have a problem when I want to edit an existing user from the Backend (using SonataAdminBundle and FOSUserBundle). In configureFormFields method of my UserAdmin class, the password field appears empty and this is a problem when I need to edit another fields (for example the lastname) keeping the same user password. This field (and the password verification field) must be filled again! (I do not want modify 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 prePersist and preUpdate methods in my UserAdmin class, but these do not work. The password is encripted in the database following the FOS standard (with salt and sha512).

Any solution? Many thanks!

like image 831
jfontecha Avatar asked Feb 06 '14 16:02

jfontecha


3 Answers

You can override your the preUpdate function in your admin class this is how i have done

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' => '/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[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' => '/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[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*/
  }
like image 161
M Khalid Junaid Avatar answered Nov 16 '22 15:11

M Khalid Junaid


I have the same problem than you but without SonataAdminBundle.

In a classic user 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',
        ));
    }
}

Don't forget to remove @Assert\NotBlank() on plainPassword in your User Entity :

/**
 * @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, password is required when you create a new user, but it isn't when you edit one.

like image 2
Eve Avatar answered Nov 16 '22 16:11

Eve


Maybe too late but useful for others. With 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/user-bundle/Resources/config/validation.xml

like image 1
user3562792 Avatar answered Nov 16 '22 15:11

user3562792