PasswordResetConfirm::process()   B
last analyzed

Complexity

Conditions 9
Paths 20

Size

Total Lines 64
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 39
c 1
b 0
f 0
nc 20
nop 1
dl 0
loc 64
rs 7.7404

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
 * Copyright (C) 2020-2025 Iain Cambridge
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
10
 * the Free Software Foundation, either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Parthenon\User\RequestProcessor;
23
24
use Parthenon\Common\Exception\NoEntityFoundException;
25
use Parthenon\Common\LoggerAwareTrait;
26
use Parthenon\Common\RequestHandler\JsonRequestHandler;
27
use Parthenon\Common\RequestHandler\RequestHandlerManagerInterface;
28
use Parthenon\User\Entity\UserInterface;
29
use Parthenon\User\Event\PostPasswordResetConfirmEvent;
30
use Parthenon\User\Event\PostUserConfirmEvent;
31
use Parthenon\User\Event\PrePasswordResetConfirmEvent;
32
use Parthenon\User\Repository\ForgotPasswordCodeRepositoryInterface;
33
use Parthenon\User\Repository\UserRepositoryInterface;
34
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
35
use Symfony\Component\HttpFoundation\JsonResponse;
36
use Symfony\Component\HttpFoundation\RedirectResponse;
37
use Symfony\Component\HttpFoundation\Request;
38
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
39
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
40
41
class PasswordResetConfirm
42
{
43
    use LoggerAwareTrait;
44
45
    public function __construct(
46
        private UserRepositoryInterface $userRepository,
47
        private ForgotPasswordCodeRepositoryInterface $forgotPasswordCodeRepository,
48
        private PasswordHasherFactoryInterface $encoderFactory,
49
        private EventDispatcherInterface $eventDispatcher,
50
        private UrlGeneratorInterface $urlGenerator,
51
        private RequestHandlerManagerInterface $requestHandlerManager,
52
    ) {
53
    }
54
55
    public function process(Request $request)
56
    {
57
        $requestHandler = $this->requestHandlerManager->getRequestHandler($request);
58
59
        $code = $request->get('code');
60
        try {
61
            $passwordReset = $this->forgotPasswordCodeRepository->findActiveByCode($code);
62
        } catch (NoEntityFoundException $e) {
63
            return $requestHandler->generateErrorOutput(null);
64
        }
65
66
        if ($passwordReset->isUsed()) {
67
            $this->getLogger()->warning('A user has tried to reset their password with an used code', ['code' => $code]);
68
69
            return $requestHandler->generateErrorOutput(null);
70
        }
71
72
        if ($passwordReset->isExpired()) {
73
            $this->getLogger()->warning('A user has tried to reset their password with an expired code', ['code' => $code]);
74
75
            return $requestHandler->generateErrorOutput(null);
76
        }
77
78
        if (!$request->isMethod('POST')) {
79
            return $requestHandler->generateDefaultOutput(null);
80
        }
81
82
        $passwordReset->setUsed(true);
83
        $passwordReset->setUsedAt(new \DateTime('now'));
84
        /** @var UserInterface $user */
85
        $user = $this->userRepository->getById($passwordReset->getUserId());
86
87
        $this->eventDispatcher->dispatch(new PrePasswordResetConfirmEvent($user), PrePasswordResetConfirmEvent::NAME);
88
89
        if ($requestHandler instanceof JsonRequestHandler) {
90
            $json = json_decode($request->getContent(), true);
91
            $newPassword = $json['password'];
92
        } else {
93
            $newPassword = $request->get('password');
94
        }
95
        $newPasswordHash = $this->encoderFactory->getPasswordHasher($user)->hash($newPassword);
96
97
        $user->setPassword($newPasswordHash);
98
        $hasActivatedUser = false;
99
        if (!$user->isConfirmed()) {
100
            $user->setActivatedAt(new \DateTime('now'));
101
            $user->setIsConfirmed(true);
102
            $hasActivatedUser = true;
103
        }
104
        $this->userRepository->save($user);
105
        $this->forgotPasswordCodeRepository->save($passwordReset);
106
107
        if ($hasActivatedUser) {
108
            $this->eventDispatcher->dispatch(new PostUserConfirmEvent($user), PostUserConfirmEvent::NAME);
109
        }
110
111
        $this->eventDispatcher->dispatch(new PostPasswordResetConfirmEvent($user), PostPasswordResetConfirmEvent::NAME);
112
        $this->getLogger()->info('A user has reset their password', ['email' => $user->getEmail()]);
113
114
        if ($requestHandler instanceof JsonRequestHandler) {
115
            return new JsonResponse(['success' => true]);
116
        }
117
118
        return new RedirectResponse($this->urlGenerator->generate('parthenon_user_login'));
119
    }
120
}
121