Search code examples
symfonyconstraintssymfony4

How to use constraints in controller


I've been trying to add a edit-user page where they can change username, email address and password.

One thing I am trying to implement is they have to type in the old password to be able to change it to a new one.

I've been reading these pages:

but I'm really struggling on the implementation side.

Here's my Controller for the form:

<?php
    namespace App\Controller\User;

    use App\Entity\User;
    use App\Form\User\EditUserType;
    use App\Repository\UserRepository;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

    class EditController extends Controller
    {
        public function edit(Request $request, UserPasswordEncoderInterface $encoder)
        {
            $userInfo = ['username' => null, 'plainPassword' => null, 'password' => null, 'email' => null];

            $form = $this->createForm(EditUserType::class, $userInfo);
            $form->handleRequest($request);

            $user        = new User();
            $oldPassword = $user->getPassword();

            if ($form->isSubmitted() && $form->isValid()) {
                $userInfo = $form->getData();

                $username = $userInfo['username'];
                $email    = $userInfo['email'];
                $newPass  = $userInfo['plainPassword'];
                $oldPass  = $userInfo['password'];

                $encryptOldPass = $encoder->encodePassword($user, $oldPass);

                if ($oldPassword === $encryptOldPass) {
                    $this->addFlash('danger', $oldPass. ' ' .$encryptOldPass. ' ' .$oldPassword);
                    return $this->redirectToRoute('user_edit');
                } else {
                    $this->addFlash('success', $oldPassword. '-' .$encryptOldPass);
                    return $this->redirectToRoute('user_edit');
                }

                $pass = $encoder->encodePassword($user, $newPass);

                $user->setPassword($pass);
                $user->setEmail($email);
                $user->setUsername($username);

                echo 'trey was here';

                $this->addFlash('success', 'User Details Edited');

                return $this->redirectToRoute('user_edit');
            }

            return $this->render('user/edit.html.twig', array('form' => $form->createView()));
        }
    }

my EditUserType file:

<?php
    namespace App\Form\User;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\Extension\Core\Type\EmailType;
    use Symfony\Component\Form\Extension\Core\Type\PasswordType;
    use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;

    class EditUserType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('email', EmailType::class)
                ->add('username', TextType::class)
                ->add('password', PasswordType::class, array())
                ->add('plainPassword', RepeatedType::class, array(
                    'type' => PasswordType::class,
                    'first_options' => array('label' => 'New Password'),
                    'second_options' => array('label' => 'New Repeat Password')
                ));
        }

        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array());
        }
    }

my validation (file: config/validator/validation.yaml)

App\Form\User\EditUserType:
    properties:
        oldPassword:
            - Symfony\Component\Security\Core\Validator\Constraints\UserPassword:
                message: 'Invalid Password'

my template file:

{% include 'builder/header.html.twig' %}

<div class="user-container" id="user-content">
    {% block body %}
        {% include 'builder/notices.html.twig' %}

        <div class="user-container">
            <i class="fas fa-user-edit fa-5x"></i>
        </div>

        <hr />

        {{ form_start(form) }}
            {{ form_row(form.username, { 'attr': {'class': 'form-control', 'value': app.user.username} }) }}
            {{ form_row(form.email, { 'attr': {'class': 'form-control', 'value': app.user.email} }) }}
            {{ form_row(form.password, { 'attr': {'class': 'form-control'} }) }}
            {{ form_row(form.plainPassword.first, { 'attr': {'class': 'form-control'} }) }}
            {{ form_row(form.plainPassword.second, { 'attr': {'class': 'form-control'} }) }}

            <div class="register-btn-container">
                <button class="btn btn-danger" id="return-to-dash-btn" type="button">Cancel!</button>
                <button class="btn btn-primary" type="submit">Update!</button>
            </div>
        {{ form_end(form) }}
    {% endblock %}
</div>

{% include 'builder/footer.html.twig' %}

Typing in any old password for the old password fields seems to get by and not update the password to the newly typed value.. so how do I validate the old password against the database so the user can update it to a new password?

Thanks


Solution

  • Found the solution, using cerad comment on previous (now removed) answer:

    updated controller:

    <?php
        namespace App\Controller\User;
    
        use App\Form\User\EditUserType;
        use Symfony\Bundle\FrameworkBundle\Controller\Controller;
        use Symfony\Component\HttpFoundation\Request;
        use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
    
    
        class EditController extends Controller
        {
            public function edit(Request $request, UserPasswordEncoderInterface $encoder)
            {
                $userInfo = ['username' => null, 'plainPassword' => null, 'password' => null, 'email' => null];
    
                $form = $this->createForm(EditUserType::class, $userInfo);
                $form->handleRequest($request);
    
                $user = $this->getUser();
    
                $entityManager = $this->getDoctrine()->getManager();
    
                if ($form->isSubmitted() && $form->isValid()) {
                    $userInfo = $form->getData();
    
                    $username = $userInfo['username'];
                    $email    = $userInfo['email'];
                    $newPass  = $userInfo['plainPassword'];
                    $oldPass  = $userInfo['password'];
    
                    if (!$encoder->isPasswordValid($user, $oldPass)) {
                        $this->addFlash('danger', 'Old password is invalid. Please try again');
                        return $this->redirectToRoute('user_edit');
                    }
    
                    $pass = $encoder->encodePassword($user, $newPass);
    
                    $user->setPassword($pass);
                    $user->setEmail($email);
                    $user->setUsername($username);
    
                    $entityManager->persist($user);
                    $entityManager->flush();
    
                    $this->addFlash('success', 'User Details Edited - Please Login Again');
    
                    return $this->redirectToRoute('login');
                }
    
                return $this->render('user/edit.html.twig', array('form' => $form->createView()));
            }
        }
    

    the issue was, I wasn't checking the logged in user details, and I thought persist meant insert, not insert/update - so lack of knowledge on this one.