Failed Conditions
Pull Request — 4.0 (#3452)
by k-yamamura
298:21 queued 232:10
created

AdminController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1.0233

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 8
dl 0
loc 19
ccs 5
cts 7
cp 0.7143
crap 1.0233
rs 9.6333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\Admin;
15
16
use Carbon\Carbon;
17
use Doctrine\Common\Collections\Criteria;
18
use Doctrine\ORM\NoResultException;
19
use Doctrine\ORM\Query\ResultSetMapping;
20
use Eccube\Controller\AbstractController;
21
use Eccube\Entity\Master\CustomerStatus;
22
use Eccube\Entity\Master\OrderStatus;
23
use Eccube\Entity\Master\ProductStatus;
24
use Eccube\Entity\ProductStock;
25
use Eccube\Event\EccubeEvents;
26
use Eccube\Event\EventArgs;
27
use Eccube\Form\Type\Admin\ChangePasswordType;
28
use Eccube\Form\Type\Admin\LoginType;
29
use Eccube\Repository\CustomerRepository;
30
use Eccube\Repository\Master\OrderStatusRepository;
31
use Eccube\Repository\MemberRepository;
32
use Eccube\Repository\OrderRepository;
33
use Eccube\Repository\ProductRepository;
34
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
35
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
36
use Symfony\Component\HttpFoundation\Request;
37
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
38
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
39
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
40
41
class AdminController extends AbstractController
42
{
43
    /**
44
     * @var AuthorizationCheckerInterface
45
     */
46
    protected $authorizationChecker;
47
48
    /**
49
     * @var AuthenticationUtils
50
     */
51
    protected $helper;
52
53
    /**
54
     * @var MemberRepository
55
     */
56
    protected $memberRepository;
57
58
    /**
59
     * @var EncoderFactoryInterface
60
     */
61
    protected $encoderFactory;
62
63
    /**
64
     * @var OrderRepository
65
     */
66
    protected $orderRepository;
67
68 10
    /**
69
     * @var OrderStatusRepository
70
     */
71
    protected $orderStatusRepository;
72
73
    /**
74 10
     * @var CustomerRepository
75 10
     */
76 10
    protected $customerRepository;
77 10
78
    /**
79
     * @var ProductRepository
80
     */
81
    protected $productRepository;
82
83
    /**
84 2
     * @var array 売り上げ状況用受注状況
85
     */
86 2
    private $excludes = [OrderStatus::PROCESSING, OrderStatus::CANCEL, OrderStatus::PENDING];
87
88
    /**
89
     * AdminController constructor.
90
     *
91 2
     * @param AuthorizationCheckerInterface $authorizationChecker
92
     * @param AuthenticationUtils $helper
93 2
     * @param MemberRepository $memberRepository
94
     * @param EncoderFactoryInterface $encoderFactory
95 2
     * @param OrderRepository $orderRepository
96
     * @param OrderStatusRepository $orderStatusRepository
97 2
     * @param CustomerRepository $custmerRepository
98
     * @param ProductRepository $productRepository
99 2
     */
100
    public function __construct(
101 2
        AuthorizationCheckerInterface $authorizationChecker,
102
        AuthenticationUtils $helper,
103
        MemberRepository $memberRepository,
104 2
        EncoderFactoryInterface $encoderFactory,
105 2
        OrderRepository $orderRepository,
106
        OrderStatusRepository $orderStatusRepository,
107
        CustomerRepository $custmerRepository,
108
        ProductRepository $productRepository
109
    ) {
110
        $this->authorizationChecker = $authorizationChecker;
111
        $this->helper = $helper;
112
        $this->memberRepository = $memberRepository;
113 4
        $this->encoderFactory = $encoderFactory;
114
        $this->orderRepository = $orderRepository;
115
        $this->orderStatusRepository = $orderStatusRepository;
116 4
        $this->customerRepository = $custmerRepository;
117
        $this->productRepository = $productRepository;
118
    }
119
120
    /**
121
     * @Route("/%eccube_admin_route%/login", name="admin_login")
122
     * @Template("@admin/login.twig")
123
     */
124
    public function login(Request $request)
125
    {
126
        if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
127
            return $this->redirectToRoute('admin_homepage');
128
        }
129
130 4
        /* @var $form \Symfony\Component\Form\FormInterface */
131
        $builder = $this->formFactory->createNamedBuilder('', LoginType::class);
132 4
133
        $event = new EventArgs(
134 4
            [
135
                'builder' => $builder,
136 4
            ],
137
            $request
138 4
        );
139 4
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIM_LOGIN_INITIALIZE, $event);
140 4
141
        $form = $builder->getForm();
142 4
143
        return [
144 4
            'error' => $this->helper->getLastAuthenticationError(),
145
            'form' => $form->createView(),
146
        ];
147 4
    }
148
149
    /**
150 4
     * 管理画面ホーム
151
     *
152
     * @param Request $request
153 4
     *
154
     * @return array
155
     *
156
     * @throws NoResultException
157
     * @throws \Doctrine\ORM\NonUniqueResultException
158 4
     *
159 4
     * @Route("/%eccube_admin_route%/", name="admin_homepage")
160 4
     * @Template("@admin/index.twig")
161 4
     */
162 4
    public function index(Request $request)
163
    {
164 4
        /**
165
         * 受注状況.
166 4
         */
167
        $excludes = [];
168 4
        $excludes[] = OrderStatus::PENDING;
169
        $excludes[] = OrderStatus::PROCESSING;
170 4
        $excludes[] = OrderStatus::CANCEL;
171 4
        $excludes[] = OrderStatus::DELIVERED;
172
173
        $event = new EventArgs(
174 4
            [
175
                'excludes' => $excludes,
176 4
            ],
177
            $request
178
        );
179
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIM_INDEX_ORDER, $event);
180
        $excludes = $event->getArgument('excludes');
181 4
182 4
        // 受注ステータスごとの受注件数.
183 4
        $Orders = $this->getOrderEachStatus($excludes);
184 4
185
        // 受注ステータスの一覧.
186 4
        $Criteria = new Criteria();
187
        $Criteria
188 4
            ->where($Criteria::expr()->notIn('id', $excludes))
189
            ->orderBy(['sort_no' => 'ASC']);
190 4
        $OrderStatuses = $this->orderStatusRepository->matching($Criteria);
191
192 4
        /**
193 4
         * 売り上げ状況
194
         */
195
        $event = new EventArgs(
196 4
            [
197
                'excludes' => $this->excludes,
198 4
            ],
199
            $request
200 4
        );
201
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIM_INDEX_SALES, $event);
202
        $this->excludes = $event->getArgument('excludes');
0 ignored issues
show
Documentation Bug introduced by
It seems like $event->getArgument('excludes') of type * is incompatible with the declared type array of property $excludes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
203
204
        // 今日の売上/件数
205
        $salesToday = $this->getSalesByDay(new \DateTime());
206 4
        // 昨日の売上/件数
207
        $salesYesterday = $this->getSalesByDay(new \DateTime('-1 day'));
208 4
        // 今月の売上/件数
209
        $salesThisMonth = $this->getSalesByMonth(new \DateTime());
210 4
211
        /**
212 4
         * ショップ状況
213 4
         */
214 4
        // 在庫切れ商品数
215 4
        $countNonStockProducts = $this->countNonStockProducts();
216 4
217 4
        // 取り扱い商品数
218 4
        $countProducts = $this->countProducts();
219
220 4
        // 本会員数
221
        $countCustomers = $this->countCustomers();
222 4
223
        $event = new EventArgs(
224
            [
225 4
                'Orders' => $Orders,
226 4
                'OrderStatuses' => $OrderStatuses,
227 4
                'salesThisMonth' => $salesThisMonth,
228 4
                'salesToday' => $salesToday,
229 4
                'salesYesterday' => $salesYesterday,
230 4
                'countNonStockProducts' => $countNonStockProducts,
231 4
                'countProducts' => $countProducts,
232 4
                'countCustomers' => $countCustomers,
233 4
            ],
234 4
            $request
235
        );
236
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIM_INDEX_COMPLETE, $event);
237
238
        return [
239
            'Orders' => $Orders,
240
            'OrderStatuses' => $OrderStatuses,
241
            'salesThisMonth' => $salesThisMonth,
242
            'salesToday' => $salesToday,
243
            'salesYesterday' => $salesYesterday,
244
            'countNonStockProducts' => $countNonStockProducts,
245
            'countProducts' => $countProducts,
246
            'countCustomers' => $countCustomers,
247
        ];
248 3
    }
249
250 3
    /**
251 3
     * 売上状況の取得
252
     *
253 3
     * @param Request $request
254
     *
255 3
     * @Route("/%eccube_admin_route%/sale_chart", name="admin_homepage_sale")
256
     *
257 3
     * @return \Symfony\Component\HttpFoundation\JsonResponse
258
     */
259 3
    public function sale(Request $request)
260
    {
261 3
        if (!($request->isXmlHttpRequest() && $this->isTokenValid())) {
262 3
            return $this->json(['status' => 'NG'], 400);
263
        }
264 3
265 1
        // 週間の売上金額
266 1
        $toDate = Carbon::now();
267 1
        $fromDate = Carbon::today()->subWeek();
268
        $rawWeekly = $this->getData($fromDate, $toDate, 'Y/m/d');
269 1
270
        // 月間の売上金額
271
        $fromDate = Carbon::now()->startOfMonth();
272 1
        $rawMonthly = $this->getData($fromDate, $toDate, 'Y/m/d');
273
274
        // 年間の売上金額
275
        $fromDate = Carbon::now()->subYear()->startOfMonth();
276 1
        $rawYear = $this->getData($fromDate, $toDate, 'Y/m');
277
278
        $datas = [$rawWeekly, $rawMonthly, $rawYear];
279 1
280 1
        return $this->json($datas);
281
    }
282 1
283
    /**
284 1
     * パスワード変更画面
285
     *
286 1
     * @Route("/%eccube_admin_route%/change_password", name="admin_change_password")
287 1
     * @Template("@admin/change_password.twig")
288
     *
289 1
     * @param Request $request
290
     *
291 1
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|array
292
     */
293 1
    public function changePassword(Request $request)
294
    {
295 1
        $builder = $this->formFactory
296
            ->createBuilder(ChangePasswordType::class);
297
298
        $event = new EventArgs(
299 2
            [
300
                'builder' => $builder,
301
            ],
302
            $request
303
        );
304
        $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIM_CHANGE_PASSWORD_INITIALIZE, $event);
305
306
        $form = $builder->getForm();
307
        $form->handleRequest($request);
308
309
        if ($form->isSubmitted() && $form->isValid()) {
310
            $Member = $this->getUser();
311
            $salt = $Member->getSalt();
312 2
            $password = $form->get('change_password')->getData();
313
314
            $encoder = $this->encoderFactory->getEncoder($Member);
0 ignored issues
show
Documentation introduced by
$Member is of type null|object, but the function expects a object<Symfony\Component...r\UserInterface>|string.

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...
315
316 2
            // 2系からのデータ移行でsaltがセットされていない場合はsaltを生成.
317 2
            if (empty($salt)) {
318 2
                $salt = $encoder->createSalt();
319
            }
320 2
321 2
            $password = $encoder->encodePassword($password, $salt);
322
323 1
            $Member
324 1
                ->setPassword($password)
325 1
                ->setSalt($salt);
326 1
327
            $this->memberRepository->save($Member);
0 ignored issues
show
Documentation introduced by
$Member is of type null|object, but the function expects a object<Eccube\Entity\Member>.

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...
328 1
329 1
            $event = new EventArgs(
330 1
                [
331
                    'form' => $form,
332
                    'Member' => $Member,
333 1
                ],
334
                $request
335
            );
336
            $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_ADMIN_CHANGE_PASSWORD_COMPLETE, $event);
337
338
            $this->addSuccess('admin.change_password.save.complete', 'admin');
339
340
            return $this->redirectToRoute('admin_change_password');
341
        }
342 4
343
        return [
344
            'form' => $form->createView(),
345
        ];
346 4
    }
347 4
348
    /**
349
     * 在庫なし商品の検索結果を表示する.
350 4
     *
351 4
     * @Route("/%eccube_admin_route%/search_nonstock", name="admin_homepage_nonstock")
352 4
     *
353 4
     * @param Request $request
354
     *
355
     * @return \Symfony\Component\HttpFoundation\Response
356
     */
357
    public function searchNonStockProducts(Request $request)
358
    {
359
        // 在庫なし商品の検索条件をセッションに付与し, 商品マスタへリダイレクトする.
360
        $searchData = [];
361
        $searchData['stock'] = [ProductStock::OUT_OF_STOCK];
362 4
        $session = $request->getSession();
363
        $session->set('eccube.admin.product.search', $searchData);
364 4
365
        return $this->redirectToRoute('admin_product_page', [
366
            'page_no' => 1,
367
            'status' => $this->eccubeConfig['eccube_admin_product_stock_status'], ]);
368
    }
369
370
    /**
371
     * 本会員の検索結果を表示する.
372
     *
373
     * @Route("/%eccube_admin_route%/search_customer", name="admin_homepage_customer")
374
     *
375 4
     * @param Request $request
376 4
     *
377 4
     * @return \Symfony\Component\HttpFoundation\Response
378 4
     */
379 4
    public function searchCustomer(Request $request)
380 4
    {
381 4
        $searchData = [];
382 4
        $searchData['customer_status'] = [CustomerStatus::REGULAR];
383 1
        $session = $request->getSession();
384
        $session->set('eccube.admin.customer.search', $searchData);
385
386 4
        return $this->redirectToRoute('admin_customer_page', [
387
            'page_no' => 1,
388
        ]);
389
    }
390
391
    /**
392
     * @param \Doctrine\ORM\EntityManagerInterface $em
0 ignored issues
show
Bug introduced by
There is no parameter named $em. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
393
     * @param array $excludes
394
     *
395
     * @return null|Request
396 4
     */
397
    private function getOrderEachStatus(array $excludes)
398
    {
399
        $sql = 'SELECT
400 4
                    t1.order_status_id as status,
401
                    COUNT(t1.id) as count
402
                FROM
403
                    dtb_order t1
404
                WHERE
405
                    t1.order_status_id NOT IN (:excludes)
406
                GROUP BY
407
                    t1.order_status_id
408
                ORDER BY
409
                    t1.order_status_id';
410
        $rsm = new ResultSetMapping();
411
        $rsm->addScalarResult('status', 'status');
412
        $rsm->addScalarResult('count', 'count');
413 4
        $query = $this->entityManager->createNativeQuery($sql, $rsm);
414 4
        $query->setParameters([':excludes' => $excludes]);
415 4
        $result = $query->getResult();
416
        $orderArray = [];
417 4
        foreach ($result as $row) {
418
            $orderArray[$row['status']] = $row['count'];
419 4
        }
420 3
421
        return $orderArray;
422
    }
423
424 4
    /**
425
     * @param $dateTime
426
     * @return array|mixed
427
     * @throws \Doctrine\ORM\NonUniqueResultException
428
     */
429 View Code Duplication
    private function getSalesByDay($dateTime)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
430
    {
431
        // concat... for pgsql
432
        // http://stackoverflow.com/questions/1091924/substr-does-not-work-with-datatype-timestamp-in-postgres-8-3
433
        $dql = 'SELECT
434 4
                  SUBSTRING(CONCAT(o.order_date, \'\'), 1, 10) AS order_day,
435
                  SUM(o.payment_total) AS order_amount,
436
                  COUNT(o) AS order_count
437
                FROM
438 4
                  Eccube\Entity\Order o
439
                WHERE
440
                    o.OrderStatus NOT IN (:excludes)
441
                    AND SUBSTRING(CONCAT(o.order_date, \'\'), 1, 10) = SUBSTRING(:targetDate, 1, 10)
442
                GROUP BY
443
                  order_day';
444
445
        $q = $this->entityManager
446
            ->createQuery($dql)
447
            ->setParameter(':excludes', $this->excludes)
448
            ->setParameter(':targetDate', $dateTime);
449
450
        $result = [];
451 4
        try {
452 4
            $result = $q->getSingleResult();
453 4
        } catch (NoResultException $e) {
454
            // 結果がない場合は空の配列を返す.
455 4
        }
456
457 4
        return $result;
458 3
    }
459
460
    /**
461
     * @param $dateTime
462 4
     * @return array|mixed
463
     * @throws \Doctrine\ORM\NonUniqueResultException
464
     */
465 View Code Duplication
    private function getSalesByMonth($dateTime)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
466
    {
467
        // concat... for pgsql
468
        // http://stackoverflow.com/questions/1091924/substr-does-not-work-with-datatype-timestamp-in-postgres-8-3
469
        $dql = 'SELECT
470
                  SUBSTRING(CONCAT(o.order_date, \'\'), 1, 7) AS order_month,
471
                  SUM(o.payment_total) AS order_amount,
472
                  COUNT(o) AS order_count
473 4
                FROM
474
                  Eccube\Entity\Order o
475
                WHERE
476 4
                    o.OrderStatus NOT IN (:excludes)
477 4
                    AND SUBSTRING(CONCAT(o.order_date, \'\'), 1, 7) = SUBSTRING(:targetDate, 1, 7)
478 4
                GROUP BY
479 4
                  order_month';
480 4
481 4
        $q = $this->entityManager
482
            ->createQuery($dql)
483
            ->setParameter(':excludes', $this->excludes)
484 4
            ->setParameter(':targetDate', $dateTime);
485 4
486
        $result = [];
487
        try {
488
            $result = $q->getSingleResult();
489
        } catch (NoResultException $e) {
490
            // 結果がない場合は空の配列を返す.
491
        }
492
493
        return $result;
494
    }
495
496 4
    /**
497
     * 在庫切れ商品数を取得
498
     *
499 4
     * @return mixed
500 4
     *
501
     * @throws \Doctrine\ORM\NonUniqueResultException
502
     */
503 4
    private function countNonStockProducts()
504 4
    {
505 4
        $qb = $this->productRepository->createQueryBuilder('p')
506 4
            ->select('count(DISTINCT p.id)')
507 4
            ->innerJoin('p.ProductClasses', 'pc')
508
            ->where('pc.stock_unlimited = :StockUnlimited AND pc.stock = 0')
509
            ->setParameter('StockUnlimited', false);
510 4
511 4
        return $qb->getQuery()->getSingleScalarResult();
512
    }
513
514
    /**
515
     * 商品数を取得
516
     *
517
     * @return mixed
518
     *
519
     * @throws \Doctrine\ORM\NonUniqueResultException
520
     */
521
    private function countProducts()
522
    {
523
        $qb = $this->productRepository->createQueryBuilder('p')
524
            ->select('count(p.id)')
525
            ->where('p.Status in (:Status)')
526
            ->setParameter('Status', [ProductStatus::DISPLAY_SHOW, ProductStatus::DISPLAY_HIDE]);
527
528
        return $qb->getQuery()->getSingleScalarResult();
529
    }
530
531
    /**
532
     * 本会員数を取得
533
     *
534
     * @return mixed
535
     *
536
     * @throws \Doctrine\ORM\NonUniqueResultException
537
     */
538
    private function countCustomers()
539
    {
540
        $qb = $this->customerRepository->createQueryBuilder('c')
541
            ->select('count(c.id)')
542
            ->where('c.Status = :Status')
543
            ->setParameter('Status', CustomerStatus::REGULAR);
544
545
        return $qb->getQuery()->getSingleScalarResult();
546
    }
547
548
    /**
549
     * 期間指定のデータを取得
550
     *
551
     * @param Carbon $fromDate
552
     * @param Carbon $toDate
553
     * @param $format
554
     *
555
     * @return array
556
     */
557
    private function getData(Carbon $fromDate, Carbon $toDate, $format)
558
    {
559
        $qb = $this->orderRepository->createQueryBuilder('o')
560
            ->andWhere('o.order_date >= :fromDate')
561
            ->andWhere('o.order_date <= :toDate')
562
            ->andWhere('o.OrderStatus NOT IN (:excludes)')
563
            ->setParameter(':excludes', $this->excludes)
564
            ->setParameter(':fromDate', $fromDate->copy())
565
            ->setParameter(':toDate', $toDate->copy())
566
            ->orderBy('o.order_date');
567
568
        $result = $qb->getQuery()->getResult();
569
570
        return $this->convert($result, $fromDate, $toDate, $format);
571
    }
572
573
    /**
574
     * 期間毎にデータをまとめる
575
     *
576
     * @param $result
577
     * @param Carbon $fromDate
578
     * @param Carbon $toDate
579
     * @param $format
580
     *
581
     * @return array
582
     */
583
    private function convert($result, Carbon $fromDate, Carbon $toDate, $format)
584
    {
585
        $raw = [];
586
        for ($date = $fromDate; $date <= $toDate; $date = $date->addDay()) {
587
            $raw[$date->format($format)]['price'] = 0;
588
            $raw[$date->format($format)]['count'] = 0;
589
        }
590
591
        foreach ($result as $Order) {
592
            $raw[$Order->getOrderDate()->format($format)]['price'] += $Order->getPaymentTotal();
593
            ++$raw[$Order->getOrderDate()->format($format)]['count'];
594
        }
595
596
        return $raw;
597
    }
598
}
599