Completed
Pull Request — experimental/sf (#3309)
by
unknown
121:53 queued 114:32
created

ForgotController::index()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 65

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 11.1035

Importance

Changes 0
Metric Value
cc 5
nc 4
nop 1
dl 0
loc 65
ccs 12
cts 32
cp 0.375
crap 11.1035
rs 8.4525
c 0
b 0
f 0

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
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Controller;
15
16
use Eccube\Event\EccubeEvents;
17
use Eccube\Event\EventArgs;
18
use Eccube\Form\Type\Front\ForgotType;
19
use Eccube\Repository\CustomerRepository;
20
use Eccube\Service\MailService;
21
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
22
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\HttpKernel\Exception as HttpException;
25
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
26
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
27
use Symfony\Component\Validator\Constraints as Assert;
28
use Symfony\Component\Validator\Validator\ValidatorInterface;
29
30
class ForgotController extends AbstractController
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
31
{
32
    /**
33
     * @var ValidatorInterface
34
     */
35
    protected $recursiveValidator;
36
37
    /**
38
     * @var MailService
39
     */
40
    protected $mailService;
41
42
    /**
43
     * @var CustomerRepository
44
     */
45
    protected $customerRepository;
46
47
    /**
48
     * @var EncoderFactoryInterface
49
     */
50
    protected $encoderFactory;
51
52
    /**
53
     * ForgotController constructor.
54
     *
55
     * @param ValidatorInterface $recursiveValidator
0 ignored issues
show
introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
56
     * @param MailService $mailService
0 ignored issues
show
introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
57
     * @param CustomerRepository $customerRepository
0 ignored issues
show
introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
58
     * @param EncoderFactoryInterface $encoderFactory
59
     */
60 4
    public function __construct(
61
        ValidatorInterface $recursiveValidator,
62
        MailService $mailService,
63
        CustomerRepository $customerRepository,
64
        EncoderFactoryInterface $encoderFactory
65
    ) {
66 4
        $this->recursiveValidator = $recursiveValidator;
67 4
        $this->mailService = $mailService;
68 4
        $this->customerRepository = $customerRepository;
69 4
        $this->encoderFactory = $encoderFactory;
70
    }
71
72
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$request" missing
Loading history...
73
     * パスワードリマインダ.
74
     *
75
     * @Route("/forgot", name="forgot")
76
     * @Template("Forgot/index.twig")
77
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
78 1
    public function index(Request $request)
79
    {
80 1
        if ($this->isGranted('ROLE_USER')) {
81
            throw new HttpException\NotFoundHttpException();
82
        }
83
84 1
        $builder = $this->formFactory
85 1
            ->createNamedBuilder('', ForgotType::class);
86
87 1
        $event = new EventArgs(
88
            [
89 1
                'builder' => $builder,
90
            ],
91 1
            $request
92
        );
93 1
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_FORGOT_INDEX_INITIALIZE, $event);
94
95 1
        $form = $builder->getForm();
96 1
        $form->handleRequest($request);
97
98 1
        if ($form->isSubmitted() && $form->isValid()) {
99
            $Customer = $this->customerRepository
100
                ->getRegularCustomerByEmail($form->get('login_email')->getData());
101
102
            if (!is_null($Customer)) {
103
                // リセットキーの発行・有効期限の設定
104
                $Customer
105
                    ->setResetKey($this->customerRepository->getUniqueResetKey())
106
                    ->setResetExpire(new \DateTime('+'.$this->eccubeConfig['eccube_customer_reset_expire'].' min'));
107
108
                // リセットキーを更新
109
                $this->entityManager->persist($Customer);
110
                $this->entityManager->flush();
111
112
                $event = new EventArgs(
113
                    [
114
                        'form' => $form,
115
                        'Customer' => $Customer,
116
                    ],
117
                    $request
118
                );
119
                $this->eventDispatcher->dispatch(EccubeEvents::FRONT_FORGOT_INDEX_COMPLETE, $event);
120
121
                // 完了URLの生成
122
                $reset_url = $this->generateUrl('forgot_reset', ['reset_key' => $Customer->getResetKey()], UrlGeneratorInterface::ABSOLUTE_URL);
123
124
                // メール送信
125
                $this->mailService->sendPasswordResetNotificationMail($Customer, $reset_url);
126
127
                // ログ出力
128
                log_info('send reset password mail to:'."{$Customer->getId()} {$Customer->getEmail()} {$request->getClientIp()}");
0 ignored issues
show
Coding Style introduced by
Variable "Customer" is not in valid camel caps format
Loading history...
129
            } else {
130
                log_warning(
131
                    'Un active customer try send reset password email: ',
132
                    ['Enter email' => $form->get('login_email')->getData()]
133
                );
134
            }
135
136
            return $this->redirectToRoute('forgot_complete');
137
        }
138
139
        return [
140 1
            'form' => $form->createView(),
141
        ];
142
    }
143
144
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$request" missing
Loading history...
145
     * パスワードリマインダ完了画面.
146
     *
147
     * @Route("/forgot/complete", name="forgot_complete")
148
     * @Template("Forgot/complete.twig")
149
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
150 1
    public function complete(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
151
    {
152 1
        if ($this->isGranted('ROLE_USER')) {
153
            throw new HttpException\NotFoundHttpException();
154
        }
155
156 1
        return [];
157
    }
158
159
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$request" missing
Loading history...
introduced by
Doc comment for parameter "$reset_key" missing
Loading history...
160
     * パスワード再発行実行画面.
161
     *
162
     * @Route("/forgot/reset/{reset_key}", name="forgot_reset")
163
     * @Template("Forgot/reset.twig")
164
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
165 2
    public function reset(Request $request, $reset_key)
166
    {
167 2
        if ($this->isGranted('ROLE_USER')) {
168
            throw new HttpException\NotFoundHttpException();
169
        }
170
171 2
        $errors = $this->recursiveValidator->validate(
172 2
            $reset_key,
173
            [
174 2
                new Assert\NotBlank(),
175 2
                new Assert\Regex(
176
                    [
177 2
                        'pattern' => '/^[a-zA-Z0-9]+$/',
178
                    ]
179
                ),
180
            ]
181
        );
182
183 2
        if ('GET' === $request->getMethod()
184 2
            && count($errors) === 0
185
        ) {
186 1
            $Customer = $this->customerRepository
187 1
                ->getRegularCustomerByResetKey($reset_key);
188 1
            if (is_null($Customer)) {
189 1
                throw new HttpException\NotFoundHttpException(trans('forgotcontroller.text.error.url'));
190
            }
191
192
            // パスワードの発行・更新
193
            $encoder = $this->encoderFactory->getEncoder($Customer);
194
            $pass = $this->customerRepository->getResetPassword();
195
            $Customer->setPassword($pass);
196
197
            // 発行したパスワードの暗号化
198
            if ($Customer->getSalt() === null) {
199
                $Customer->setSalt($this->encoderFactory->getEncoder($Customer)->createSalt());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Securi...asswordEncoderInterface as the method createSalt() does only exist in the following implementations of said interface: Eccube\Security\Core\Encoder\PasswordEncoder.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
200
            }
201
            $encPass = $encoder->encodePassword($pass, $Customer->getSalt());
202
            $Customer->setPassword($encPass);
203
204
            $Customer->setResetKey(null);
205
206
            // パスワードを更新
207
            $this->entityManager->persist($Customer);
208
            $this->entityManager->flush();
209
210
            $event = new EventArgs(
211
                [
212
                    'Customer' => $Customer,
213
                ],
214
                $request
215
            );
216
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_FORGOT_RESET_COMPLETE, $event);
217
218
            // メール送信
219
            $this->mailService->sendPasswordResetCompleteMail($Customer, $pass);
220
            // ログ出力
221
            log_info('reset password complete:'."{$Customer->getId()} {$Customer->getEmail()} {$request->getClientIp()}");
0 ignored issues
show
Coding Style introduced by
Variable "Customer" is not in valid camel caps format
Loading history...
222
        } else {
223 1
            throw new HttpException\AccessDeniedHttpException(trans('forgotcontroller.text.error.authorization'));
224
        }
225
226
        return [];
227
    }
228
}
229