Completed
Pull Request — experimental/sf (#3456)
by Kiyotaka
87:43 queued 81:34
created

ProductController::getPageTitle()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 5.1158

Importance

Changes 0
Metric Value
cc 5
nc 3
nop 1
dl 0
loc 10
rs 9.6111
c 0
b 0
f 0
ccs 5
cts 6
cp 0.8333
crap 5.1158
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\Entity\BaseInfo;
17
use Eccube\Entity\Master\ProductStatus;
18
use Eccube\Entity\Product;
19
use Eccube\Event\EccubeEvents;
20
use Eccube\Event\EventArgs;
21
use Eccube\Form\Type\AddCartType;
22
use Eccube\Form\Type\Master\ProductListMaxType;
23
use Eccube\Form\Type\Master\ProductListOrderByType;
24
use Eccube\Form\Type\SearchProductType;
25
use Eccube\Repository\BaseInfoRepository;
26
use Eccube\Repository\CustomerFavoriteProductRepository;
27
use Eccube\Repository\ProductRepository;
28
use Eccube\Service\CartService;
29
use Eccube\Service\PurchaseFlow\PurchaseContext;
30
use Eccube\Service\PurchaseFlow\PurchaseFlow;
31
use Knp\Component\Pager\Paginator;
32
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
33
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
34
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
35
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
36
use Symfony\Component\HttpFoundation\Request;
37
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
38
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
39
40
class ProductController extends AbstractController
41
{
42
    /**
43
     * @var PurchaseFlow
44
     */
45
    protected $purchaseFlow;
46
47
    /**
48
     * @var CustomerFavoriteProductRepository
49
     */
50
    protected $customerFavoriteProductRepository;
51
52
    /**
53
     * @var CartService
54
     */
55
    protected $cartService;
56
57
    /**
58
     * @var ProductRepository
59
     */
60
    protected $productRepository;
61
62
    /**
63
     * @var BaseInfo
64
     */
65
    protected $BaseInfo;
66
67
    /**
68
     * @var AuthenticationUtils
69
     */
70
    protected $helper;
71
72
    private $title = '';
73
74
    /**
75
     * ProductController constructor.
76
     *
77
     * @param PurchaseFlow $cartPurchaseFlow
78
     * @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
79
     * @param CartService $cartService
80
     * @param ProductRepository $productRepository
81
     * @param BaseInfoRepository $baseInfoRepository
82
     * @param AuthenticationUtils $helper
83
     */
84 46 View Code Duplication
    public function __construct(
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...
85
        PurchaseFlow $cartPurchaseFlow,
86
        CustomerFavoriteProductRepository $customerFavoriteProductRepository,
87
        CartService $cartService,
88
        ProductRepository $productRepository,
89
        BaseInfoRepository $baseInfoRepository,
90
        AuthenticationUtils $helper
91
    ) {
92 46
        $this->purchaseFlow = $cartPurchaseFlow;
93 46
        $this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
94 46
        $this->cartService = $cartService;
95 46
        $this->productRepository = $productRepository;
96 46
        $this->BaseInfo = $baseInfoRepository->get();
97 46
        $this->helper = $helper;
98
    }
99
100
    /**
101
     * 商品一覧画面.
102
     *
103
     * @Route("/products/list", name="product_list")
104
     * @Template("Product/list.twig")
105
     */
106 3
    public function index(Request $request, Paginator $paginator)
107
    {
108
        // Doctrine SQLFilter
109
        // if ($this->BaseInfo->isOptionNostockHidden()) {
110
        //     $this->entityManager->getFilters()->enable('option_nostock_hidden');
111
        // }
112
113
        // handleRequestは空のqueryの場合は無視するため
114 3
        if ($request->getMethod() === 'GET') {
115 3
            $request->query->set('pageno', $request->query->get('pageno', ''));
116
        }
117
118
        // searchForm
119
        /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
120 3
        $builder = $this->formFactory->createNamedBuilder('', SearchProductType::class);
121 3
        $builder->setAttribute('freeze', true);
122 3
        $builder->setAttribute('freeze_display_text', false);
123 3
        if ($request->getMethod() === 'GET') {
124 3
            $builder->setMethod('GET');
125
        }
126
127 3
        $event = new EventArgs(
128
            [
129 3
                'builder' => $builder,
130
            ],
131 3
            $request
132
        );
133 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE, $event);
134
135
        /* @var $searchForm \Symfony\Component\Form\FormInterface */
136 3
        $searchForm = $builder->getForm();
137
138 3
        $searchForm->handleRequest($request);
139
140
        // paginator
141 3
        $searchData = $searchForm->getData();
142 3
        $qb = $this->productRepository->getQueryBuilderBySearchData($searchData);
143
144 3
        $event = new EventArgs(
145
            [
146 3
                'searchData' => $searchData,
147 3
                'qb' => $qb,
148
            ],
149 3
            $request
150
        );
151 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_SEARCH, $event);
152 3
        $searchData = $event->getArgument('searchData');
153
154 3
        $pagination = $paginator->paginate(
155 3
            $qb,
156 3
            !empty($searchData['pageno']) ? $searchData['pageno'] : 1,
157 3
            $searchData['disp_number']->getId()
158
        );
159
160
        // addCart form
161 3
        $forms = [];
162 3 View Code Duplication
        foreach ($pagination as $Product) {
0 ignored issues
show
Bug introduced by
The expression $pagination of type object<Knp\Component\Pag...on\PaginationInterface> is not traversable.
Loading history...
163
            /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
164 3
            $builder = $this->formFactory->createNamedBuilder(
165 3
                '',
166 3
                AddCartType::class,
167 3
                null,
168
                [
169 3
                    'product' => $Product,
170
                    'allow_extra_fields' => true,
171
                ]
172
            );
173 3
            $addCartForm = $builder->getForm();
174
175 3
            $forms[$Product->getId()] = $addCartForm->createView();
176
        }
177
178
        // 表示件数
179 3
        $builder = $this->formFactory->createNamedBuilder(
180 3
            'disp_number',
181 3
            ProductListMaxType::class,
182 3
            null,
183
            [
184 3
                'required' => false,
185 3
                'label' => trans('productcontroller.label.result'),
186
                'allow_extra_fields' => true,
187
            ]
188
        );
189 3
        if ($request->getMethod() === 'GET') {
190 3
            $builder->setMethod('GET');
191
        }
192
193 3
        $event = new EventArgs(
194
            [
195 3
                'builder' => $builder,
196
            ],
197 3
            $request
198
        );
199 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_DISP, $event);
200
201 3
        $dispNumberForm = $builder->getForm();
202
203 3
        $dispNumberForm->handleRequest($request);
204
205
        // ソート順
206 3
        $builder = $this->formFactory->createNamedBuilder(
207 3
            'orderby',
208 3
            ProductListOrderByType::class,
209 3
            null,
210
            [
211 3
                'required' => false,
212 3
                'label' => trans('productcontroller.label.sort'),
213
                'allow_extra_fields' => true,
214
            ]
215
        );
216 3
        if ($request->getMethod() === 'GET') {
217 3
            $builder->setMethod('GET');
218
        }
219
220 3
        $event = new EventArgs(
221
            [
222 3
                'builder' => $builder,
223
            ],
224 3
            $request
225
        );
226 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_ORDER, $event);
227
228 3
        $orderByForm = $builder->getForm();
229
230 3
        $orderByForm->handleRequest($request);
231
232 3
        $Category = $searchForm->get('category_id')->getData();
233
234
        return [
235 3
            'subtitle' => $this->getPageTitle($searchData),
236 3
            'pagination' => $pagination,
237 3
            'search_form' => $searchForm->createView(),
238 3
            'disp_number_form' => $dispNumberForm->createView(),
239 3
            'order_by_form' => $orderByForm->createView(),
240 3
            'forms' => $forms,
241 3
            'Category' => $Category,
242
        ];
243
    }
244
245
    /**
246
     * 商品詳細画面.
247
     *
248
     * @Method("GET")
249
     * @Route("/products/detail/{id}", name="product_detail", requirements={"id" = "\d+"})
250
     * @Template("Product/detail.twig")
251
     * @ParamConverter("Product", options={"repository_method" = "findWithSortedClassCategories"})
252
     *
253
     * @param Request $request
254
     * @param Product $Product
255
     *
256
     * @return array
257
     */
258 11
    public function detail(Request $request, Product $Product)
259
    {
260 11
        if (!$this->checkVisibility($Product)) {
261
            throw new NotFoundHttpException();
262
        }
263
264 11
        $builder = $this->formFactory->createNamedBuilder(
265 11
            '',
266 11
            AddCartType::class,
267 11
            null,
268
            [
269 11
                'product' => $Product,
270
                'id_add_product_id' => false,
271
            ]
272
        );
273
274 11
        $event = new EventArgs(
275
            [
276 11
                'builder' => $builder,
277 11
                'Product' => $Product,
278
            ],
279 11
            $request
280
        );
281 11
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE, $event);
282
283 11
        $is_favorite = false;
284 11
        if ($this->isGranted('ROLE_USER')) {
285 2
            $Customer = $this->getUser();
286 2
            $is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
0 ignored issues
show
Documentation introduced by
$Customer is of type null|object, but the function expects a object<Eccube\Entity\Customer>.

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...
287
        }
288
289
        return [
290 11
            'title' => $this->title,
291 11
            'subtitle' => $Product->getName(),
292 11
            'form' => $builder->getForm()->createView(),
293 11
            'Product' => $Product,
294 11
            'is_favorite' => $is_favorite,
295
        ];
296
    }
297
298
    /**
299
     * お気に入り追加.
300
     *
301
     * @Route("/products/add_favorite/{id}", name="product_add_favorite", requirements={"id" = "\d+"})
302
     */
303 3
    public function addFavorite(Request $request, Product $Product)
304
    {
305 3
        $this->checkVisibility($Product);
306
307 3
        $event = new EventArgs(
308
            [
309 3
                'Product' => $Product,
310
            ],
311 3
            $request
312
        );
313 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE, $event);
314
315 3
        if ($this->isGranted('ROLE_USER')) {
316 2
            $Customer = $this->getUser();
317 2
            $this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
0 ignored issues
show
Documentation introduced by
$Customer is of type null|object, but the function expects a object<Eccube\Entity\Customer>.

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...
318 2
            $this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
319
320 2
            $event = new EventArgs(
321
                [
322 2
                    'Product' => $Product,
323
                ],
324 2
                $request
325
            );
326 2
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
327
328 2
            return $this->redirectToRoute('product_detail', ['id' => $Product->getId()]);
329
        } else {
330
            // 非会員の場合、ログイン画面を表示
331
            //  ログイン後の画面遷移先を設定
332 1
            $this->setLoginTargetPath($this->generateUrl('product_add_favorite', ['id' => $Product->getId()]));
333 1
            $this->session->getFlashBag()->set('eccube.add.favorite', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string|array.

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...
334
335 1
            $event = new EventArgs(
336
                [
337 1
                    'Product' => $Product,
338
                ],
339 1
                $request
340
            );
341 1
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
342
343 1
            return $this->redirectToRoute('mypage_login');
344
        }
345
    }
346
347
    /**
348
     * カートに追加.
349
     *
350
     * @Method("POST")
351
     * @Route("/products/add_cart/{id}", name="product_add_cart", requirements={"id" = "\d+"})
352
     */
353 37
    public function addCart(Request $request, Product $Product)
354
    {
355
        // エラーメッセージの配列
356 37
        $errorMessages = [];
357 37
        if (!$this->checkVisibility($Product)) {
358 1
            throw new NotFoundHttpException();
359
        }
360
361 36
        $builder = $this->formFactory->createNamedBuilder(
362 36
            '',
363 36
            AddCartType::class,
364 36
            null,
365
            [
366 36
                'product' => $Product,
367
                'id_add_product_id' => false,
368
            ]
369
        );
370
371 36
        $event = new EventArgs(
372
            [
373 36
                'builder' => $builder,
374 36
                'Product' => $Product,
375
            ],
376 36
            $request
377
        );
378 36
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE, $event);
379
380
        /* @var $form \Symfony\Component\Form\FormInterface */
381 36
        $form = $builder->getForm();
382 36
        $form->handleRequest($request);
383
384 36
        if (!$form->isValid()) {
385 1
            throw new NotFoundHttpException();
386
        }
387
388 35
        $addCartData = $form->getData();
389
390 35
        log_info(
391 35
            'カート追加処理開始',
392
            [
393 35
                'product_id' => $Product->getId(),
394 35
                'product_class_id' => $addCartData['product_class_id'],
395 35
                'quantity' => $addCartData['quantity'],
396
            ]
397
        );
398
399
        // カートへ追加
400 35
        $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
401
402
        // 明細の正規化
403 35
        $Carts = $this->cartService->getCarts();
404 35 View Code Duplication
        foreach ($Carts as $Cart) {
405 35
            $result = $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser()));
406
            // 復旧不可のエラーが発生した場合は追加した明細を削除.
407 35
            if ($result->hasError()) {
408
                $this->cartService->removeProduct($addCartData['product_class_id']);
409
                foreach ($result->getErrors() as $error) {
410
                    $errorMessages[] = $error->getMessage();
411
                }
412
            }
413 35
            foreach ($result->getWarning() as $warning) {
414 35
                $errorMessages[] = $warning->getMessage();
415
            }
416
        }
417
418 35
        $this->cartService->save();
419
420 35
        log_info(
421 35
            'カート追加処理完了',
422
            [
423 35
                'product_id' => $Product->getId(),
424 35
                'product_class_id' => $addCartData['product_class_id'],
425 35
                'quantity' => $addCartData['quantity'],
426
            ]
427
        );
428
429 35
        $event = new EventArgs(
430
            [
431 35
                'form' => $form,
432 35
                'Product' => $Product,
433
            ],
434 35
            $request
435
        );
436 35
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE, $event);
437
438 35
        if ($event->getResponse() !== null) {
439
            return $event->getResponse();
440
        }
441
442 35
        if ($request->isXmlHttpRequest()) {
443
            // ajaxでのリクエストの場合は結果をjson形式で返す。
444
445
            // 初期化
446
            $done = null;
0 ignored issues
show
Unused Code introduced by
$done is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
447
            $messages = [];
448
449
            if (empty($errorMessages)) {
450
                // エラーが発生していない場合
451
                $done = true;
452
                array_push($messages, 'カートに追加しました。');
453
            } else {
454
                // エラーが発生している場合
455
                $done = false;
456
                $messages = $errorMessages;
457
            }
458
459
            return $this->json(['done' => $done, 'messages' => $messages]);
460
        } else {
461
            // ajax以外でのリクエストの場合はカート画面へリダイレクト
462 35
            foreach ($errorMessages as $errorMessage) {
463 5
                $this->addRequestError($errorMessage);
464
            }
465
466 35
            return $this->redirectToRoute('cart');
467
        }
468
    }
469
470
    /**
471
     * ページタイトルの設定
472
     *
473
     * @param  null|array $searchData
474
     *
475
     * @return str
476
     */
477 3
    private function getPageTitle($searchData)
478
    {
479 3
        if (isset($searchData['name']) && !empty($searchData['name'])) {
480
            return trans('productcontroller.text.return.search');
481 3
        } elseif (isset($searchData['category_id']) && $searchData['category_id']) {
482 1
            return $searchData['category_id']->getName();
483
        } else {
484 2
            return trans('productcontroller.text.return.all_products');
485
        }
486
    }
487
488
    /**
489
     * 閲覧可能な商品かどうかを判定
490
     *
491
     * @param Product $Product
492
     *
493
     * @return boolean 閲覧可能な場合はtrue
494
     */
495 43
    private function checkVisibility(Product $Product)
496
    {
497 43
        $is_admin = $this->session->has('_security_admin');
498
499
        // 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
500 43
        if (!$is_admin) {
501
            // 在庫なし商品の非表示オプションが有効な場合.
502
            // if ($this->BaseInfo->isOptionNostockHidden()) {
503
            //     if (!$Product->getStockFind()) {
504
            //         return false;
505
            //     }
506
            // }
507
            // 公開ステータスでない商品は表示しない.
508 43
            if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
509 1
                return false;
510
            }
511
        }
512
513 43
        return true;
514
    }
515
}
516