Completed
Push — master ( affb41...f007be )
by Rafał
09:54
created

ResetPasswordController::reset()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 8.4032
c 0
b 0
f 0
cc 6
nc 5
nop 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Superdesk Web Publisher User Bundle.
7
 *
8
 * Copyright 2021 Sourcefabric z.ú. and contributors.
9
 *
10
 * For the full copyright and license information, please see the
11
 * AUTHORS and LICENSE files distributed with this source code.
12
 *
13
 * @Copyright 2021 Sourcefabric z.ú
14
 * @license http://www.superdesk.org/license
15
 */
16
17
namespace SWP\Bundle\UserBundle\Controller;
18
19
use SWP\Bundle\CoreBundle\Model\User;
20
use SWP\Bundle\UserBundle\Form\ChangePasswordFormType;
21
use SWP\Bundle\UserBundle\Form\ResetPasswordRequestFormType;
22
use SWP\Bundle\UserBundle\Mailer\MailerInterface;
23
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
24
use Symfony\Component\HttpFoundation\RedirectResponse;
25
use Symfony\Component\HttpFoundation\Request;
26
use Symfony\Component\HttpFoundation\Response;
27
use Symfony\Component\Routing\Annotation\Route;
28
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
29
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
30
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
31
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
32
33
/**
34
 * @Route("/reset-password")
35
 */
36
class ResetPasswordController extends AbstractController
37
{
38
    use ResetPasswordControllerTrait;
39
40
    private $resetPasswordHelper;
41
42
    public function __construct(ResetPasswordHelperInterface $resetPasswordHelper)
43
    {
44
        $this->resetPasswordHelper = $resetPasswordHelper;
45
    }
46
47
    /**
48
     * Display & process form to request a password reset.
49
     *
50
     * @Route("", name="swp_user_forgot_password_request")
51
     */
52
    public function request(Request $request, MailerInterface $mailer): Response
53
    {
54
        $form = $this->createForm(ResetPasswordRequestFormType::class);
55
        $form->handleRequest($request);
56
57
        if ($form->isSubmitted() && $form->isValid()) {
58
            return $this->processSendingPasswordResetEmail(
59
                $form->get('email')->getData(),
60
                $mailer
61
            );
62
        }
63
64
        return $this->render('@SWPUser/reset_password/request.html.twig', [
65
            'requestForm' => $form->createView(),
66
        ]);
67
    }
68
69
    /**
70
     * Confirmation page after a user has requested a password reset.
71
     *
72
     * @Route("/check-email", name="swp_user_check_email")
73
     */
74
    public function checkEmail(): Response
75
    {
76
        // We prevent users from directly accessing this page
77
        if (!$this->canCheckEmail()) {
0 ignored issues
show
Deprecated Code introduced by
The method SymfonyCasts\Bundle\Rese...rTrait::canCheckEmail() has been deprecated with message: since 1.3.0, use ResetPasswordControllerTrait::getTokenObjectFromSession() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
78
            return $this->redirectToRoute('swp_user_forgot_password_request');
79
        }
80
81
        return $this->render('@SWPUser/reset_password/check_email.html.twig', [
82
            'tokenLifetime' => $this->resetPasswordHelper->getTokenLifetime(),
83
        ]);
84
    }
85
86
    /**
87
     * Validates and process the reset URL that the user clicked in their email.
88
     *
89
     * @Route("/reset/{token}", name="swp_user_reset_password")
90
     */
91
    public function reset(Request $request, UserPasswordEncoderInterface $passwordEncoder, string $token = null): Response
92
    {
93
        if ($token) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $token of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
94
            // We store the token in session and remove it from the URL, to avoid the URL being
95
            // loaded in a browser and potentially leaking the token to 3rd party JavaScript.
96
            $this->storeTokenInSession($token);
97
98
            return $this->redirectToRoute('swp_user_reset_password');
99
        }
100
101
        $token = $this->getTokenFromSession();
102
        if (null === $token) {
103
            throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
104
        }
105
106
        try {
107
            $user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
108
        } catch (ResetPasswordExceptionInterface $e) {
109
            $this->addFlash('reset_password_error', sprintf(
110
                'There was a problem validating your reset request - %s',
111
                $e->getReason()
112
            ));
113
114
            return $this->redirectToRoute('swp_user_forgot_password_request');
115
        }
116
117
        // The token is valid; allow the user to change their password.
118
        $form = $this->createForm(ChangePasswordFormType::class);
119
        $form->handleRequest($request);
120
121
        if ($form->isSubmitted() && $form->isValid()) {
122
            // A password reset token should be used only once, remove it.
123
            $this->resetPasswordHelper->removeResetRequest($token);
124
125
            // Encode the plain password, and set it.
126
            $encodedPassword = $passwordEncoder->encodePassword(
127
                $user,
128
                $form->get('plainPassword')->getData()
129
            );
130
131
            $user->setPassword($encodedPassword);
132
            $this->getDoctrine()->getManager()->flush();
133
134
            // The session is cleaned up after the password has been changed.
135
            $this->cleanSessionAfterReset();
136
137
            return $this->redirectToRoute('homepage');
138
        }
139
140
        return $this->render('@SWPUser/reset_password/reset.html.twig', [
141
            'resetForm' => $form->createView(),
142
        ]);
143
    }
144
145
    private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer): RedirectResponse
146
    {
147
        $user = $this->getDoctrine()->getRepository(User::class)->findOneBy([
148
            'email' => $emailFormData,
149
        ]);
150
151
        // Marks that you are allowed to see the swp_user_check_email page.
152
        $this->setCanCheckEmailInSession();
0 ignored issues
show
Deprecated Code introduced by
The method SymfonyCasts\Bundle\Rese...anCheckEmailInSession() has been deprecated with message: since 1.3.0, use ResetPasswordControllerTrait::setTokenObjectInSession() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
153
154
        // Do not reveal whether a user account was found or not.
155
        if (!$user) {
156
            return $this->redirectToRoute('swp_user_check_email');
157
        }
158
159
        try {
160
            $resetToken = $this->resetPasswordHelper->generateResetToken($user);
161
        } catch (ResetPasswordExceptionInterface $e) {
162
            $this->addFlash('reset_password_error', sprintf(
163
                 'There was a problem handling your password reset request - %s',
164
                 $e->getReason()
165
             ));
166
167
            return $this->redirectToRoute('swp_user_check_email');
168
        }
169
170
        $mailer->sendResetPasswordEmail($user, $resetToken);
171
172
        return $this->redirectToRoute('swp_user_check_email');
173
    }
174
}
175