Completed
Pull Request — master (#91)
by Piotr
02:36
created

ActivationController::changePasswordAction()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 33
c 1
b 0
f 0
rs 8.5806
cc 4
eloc 19
nc 3
nop 2
1
<?php
2
3
/**
4
 * (c) FSi sp. z o.o. <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace FSi\Bundle\AdminSecurityBundle\Controller\Activation;
11
12
use FSi\Bundle\AdminBundle\Message\FlashMessages;
13
use FSi\Bundle\AdminSecurityBundle\Event\ActivationEvent;
14
use FSi\Bundle\AdminSecurityBundle\Event\AdminSecurityEvents;
15
use FSi\Bundle\AdminSecurityBundle\Event\ChangePasswordEvent;
16
use FSi\Bundle\AdminSecurityBundle\Security\User\ActivableInterface;
17
use FSi\Bundle\AdminSecurityBundle\Security\User\EnforceablePasswordChangeInterface;
18
use FSi\Bundle\AdminSecurityBundle\Security\User\UserRepositoryInterface;
19
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
20
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21
use Symfony\Component\Form\FormFactoryInterface;
22
use Symfony\Component\HttpFoundation\RedirectResponse;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\HttpFoundation\Response;
25
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
26
use Symfony\Component\Routing\RouterInterface;
27
28
class ActivationController
29
{
30
    /**
31
     * @var EngineInterface
32
     */
33
    private $templating;
34
35
    /**
36
     * @var string
37
     */
38
    private $changePasswordActionTemplate;
39
40
    /**
41
     * @var UserRepositoryInterface
42
     */
43
    private $userRepository;
44
45
    /**
46
     * @var RouterInterface
47
     */
48
    private $router;
49
50
    /**
51
     * @var FormFactoryInterface
52
     */
53
    private $formFactory;
54
55
    /**
56
     * @var EventDispatcherInterface
57
     */
58
    private $eventDispatcher;
59
60
    /**
61
     * @var FlashMessages
62
     */
63
    private $flashMessages;
64
65
    /**
66
     * @var string
67
     */
68
    private $changePasswordFormType;
69
70
    /**
71
     * @var array
72
     */
73
    private $changePasswordFormValidationGroups;
74
75
    /**
76
     * @param EngineInterface $templating
77
     * @param string $changePasswordActionTemplate
78
     * @param UserRepositoryInterface $userRepository
79
     * @param RouterInterface $router
80
     * @param FormFactoryInterface $formFactory
81
     * @param EventDispatcherInterface $eventDispatcher
82
     * @param FlashMessages $flashMessages
83
     * @param string $changePasswordFormType
84
     * @param array $changePasswordFormValidationGroups
85
     */
86
    public function __construct(
87
        EngineInterface $templating,
88
        $changePasswordActionTemplate,
89
        UserRepositoryInterface $userRepository,
90
        RouterInterface $router,
91
        FormFactoryInterface $formFactory,
92
        EventDispatcherInterface $eventDispatcher,
93
        FlashMessages $flashMessages,
94
        $changePasswordFormType,
95
        array $changePasswordFormValidationGroups
96
    ) {
97
        $this->templating = $templating;
98
        $this->changePasswordActionTemplate = $changePasswordActionTemplate;
99
        $this->userRepository = $userRepository;
100
        $this->router = $router;
101
        $this->formFactory = $formFactory;
102
        $this->eventDispatcher = $eventDispatcher;
103
        $this->flashMessages = $flashMessages;
104
        $this->changePasswordFormType = $changePasswordFormType;
105
        $this->changePasswordFormValidationGroups = $changePasswordFormValidationGroups;
106
    }
107
108
    /**
109
     * @param string $token
110
     * @return RedirectResponse
111
     */
112
    public function activateAction($token)
113
    {
114
        $user = $this->tryFindUserByActivationToken($token);
115
116
        if ($this->isUserEnforcedToChangePassword($user)) {
117
            $this->flashMessages->info('admin.activation.message.change_password', 'FSiAdminSecurity');
118
119
            return new RedirectResponse(
120
                $this->router->generate('fsi_admin_activation_change_password', ['token' => $token])
121
            );
122
        } else {
123
            $this->eventDispatcher->dispatch(
124
                AdminSecurityEvents::ACTIVATION,
125
                new ActivationEvent($user)
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->tryFindUserByActivationToken($token) on line 114 can be null; however, FSi\Bundle\AdminSecurity...ionEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
126
            );
127
128
            return $this->addFlashAndRedirect('success', 'admin.activation.message.success');
129
        }
130
    }
131
132
    /**
133
     * @param Request $request
134
     * @param string $token
135
     * @return RedirectResponse|Response
136
     */
137
    public function changePasswordAction(Request $request, $token)
138
    {
139
        $user = $this->tryFindUserByActivationToken($token);
140
141
        if (!$this->isUserEnforcedToChangePassword($user)) {
142
            throw new NotFoundHttpException();
143
        }
144
145
        $form = $this->formFactory->create(
146
            $this->changePasswordFormType,
147
            $user,
148
            ['validation_groups' => $this->changePasswordFormValidationGroups]
149
        );
150
151
        if ($form->handleRequest($request)->isSubmitted() && $form->isValid()) {
152
            $this->eventDispatcher->dispatch(
153
                AdminSecurityEvents::ACTIVATION,
154
                new ActivationEvent($user)
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->tryFindUserByActivationToken($token) on line 139 can be null; however, FSi\Bundle\AdminSecurity...ionEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
155
            );
156
157
            $this->eventDispatcher->dispatch(
158
                AdminSecurityEvents::CHANGE_PASSWORD,
159
                new ChangePasswordEvent($user)
0 ignored issues
show
Documentation introduced by
$user is of type object<FSi\Bundle\AdminS...ctivableInterface>|null, but the function expects a object<FSi\Bundle\AdminS...eablePasswordInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
160
            );
161
162
            return $this->addFlashAndRedirect('success', 'admin.activation.message.change_password_success');
163
        }
164
165
        return $this->templating->renderResponse(
166
            $this->changePasswordActionTemplate,
167
            ['form' => $form->createView()]
168
        );
169
    }
170
171
    /**
172
     * @param $token
173
     * @return ActivableInterface|null
174
     */
175
    private function tryFindUserByActivationToken($token)
176
    {
177
        $user = $this->userRepository->findUserByActivationToken($token);
178
179
        if (!($user instanceof ActivableInterface)) {
180
            throw new NotFoundHttpException();
181
        }
182
183
        if ($user->isEnabled()) {
184
            throw new NotFoundHttpException();
185
        }
186
187
        if (!$user->getActivationToken()->isNonExpired()) {
188
            throw new NotFoundHttpException();
189
        }
190
191
        return $user;
192
    }
193
194
    /**
195
     * @param string $type
196
     * @param string $message
197
     * @return RedirectResponse
198
     */
199
    private function addFlashAndRedirect($type, $message)
200
    {
201
        $this->flashMessages->{$type}($message, 'FSiAdminSecurity');
202
203
        return new RedirectResponse($this->router->generate('fsi_admin_security_user_login'));
204
    }
205
206
    /**
207
     * @param $user
208
     * @return bool
209
     */
210
    private function isUserEnforcedToChangePassword($user)
211
    {
212
        return ($user instanceof EnforceablePasswordChangeInterface) && $user->isForcedToChangePassword();
213
    }
214
}
215