Completed
Push — 4.0 ( 43ce70...473852 )
by Ryo
07:01
created

ProductController::checkVisibility()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 20
ccs 4
cts 4
cp 1
crap 3
rs 9.6
c 0
b 0
f 0
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\ParamConverter;
33
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
34
use Symfony\Component\HttpFoundation\Request;
35
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
36
use Symfony\Component\Routing\Annotation\Route;
37
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
38
39
class ProductController extends AbstractController
40
{
41
    /**
42
     * @var PurchaseFlow
43
     */
44
    protected $purchaseFlow;
45
46
    /**
47
     * @var CustomerFavoriteProductRepository
48
     */
49
    protected $customerFavoriteProductRepository;
50
51
    /**
52
     * @var CartService
53
     */
54
    protected $cartService;
55
56
    /**
57
     * @var ProductRepository
58
     */
59
    protected $productRepository;
60
61
    /**
62
     * @var BaseInfo
63
     */
64
    protected $BaseInfo;
65
66
    /**
67
     * @var AuthenticationUtils
68
     */
69
    protected $helper;
70
71
    private $title = '';
72
73
    /**
74
     * ProductController constructor.
75
     *
76
     * @param PurchaseFlow $cartPurchaseFlow
77
     * @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
78
     * @param CartService $cartService
79
     * @param ProductRepository $productRepository
80
     * @param BaseInfoRepository $baseInfoRepository
81
     * @param AuthenticationUtils $helper
82
     */
83
    public function __construct(
84 46
        PurchaseFlow $cartPurchaseFlow,
85
        CustomerFavoriteProductRepository $customerFavoriteProductRepository,
86
        CartService $cartService,
87
        ProductRepository $productRepository,
88
        BaseInfoRepository $baseInfoRepository,
89
        AuthenticationUtils $helper
90
    ) {
91
        $this->purchaseFlow = $cartPurchaseFlow;
92 46
        $this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
93 46
        $this->cartService = $cartService;
94 46
        $this->productRepository = $productRepository;
95 46
        $this->BaseInfo = $baseInfoRepository->get();
96 46
        $this->helper = $helper;
97 46
    }
98
99
    /**
100
     * 商品一覧画面.
101
     *
102
     * @Route("/products/list", name="product_list")
103
     * @Template("Product/list.twig")
104
     */
105
    public function index(Request $request, Paginator $paginator)
106 3
    {
107
        // Doctrine SQLFilter
108
         if ($this->BaseInfo->isOptionNostockHidden()) {
109
             $this->entityManager->getFilters()->enable('option_nostock_hidden');
110
         }
111
112
        // handleRequestは空のqueryの場合は無視するため
113
        if ($request->getMethod() === 'GET') {
114 3
            $request->query->set('pageno', $request->query->get('pageno', ''));
115 3
        }
116
117
        // searchForm
118
        /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
119
        $builder = $this->formFactory->createNamedBuilder('', SearchProductType::class);
120 3
121 3
        if ($request->getMethod() === 'GET') {
122 3
            $builder->setMethod('GET');
123 3
        }
124 3
125
        $event = new EventArgs(
126
            [
127 3
                'builder' => $builder,
128
            ],
129 3
            $request
130
        );
131 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE, $event);
132
133 3
        /* @var $searchForm \Symfony\Component\Form\FormInterface */
134
        $searchForm = $builder->getForm();
135
136 3
        $searchForm->handleRequest($request);
137
138 3
        // paginator
139
        $searchData = $searchForm->getData();
140
        $qb = $this->productRepository->getQueryBuilderBySearchData($searchData);
141 3
142 3
        $event = new EventArgs(
143
            [
144 3
                'searchData' => $searchData,
145
                'qb' => $qb,
146 3
            ],
147 3
            $request
148
        );
149 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_SEARCH, $event);
150
        $searchData = $event->getArgument('searchData');
151 3
152 3
        $pagination = $paginator->paginate(
153
            $qb,
154 3
            !empty($searchData['pageno']) ? $searchData['pageno'] : 1,
155 3
            $searchData['disp_number']->getId()
156 3
        );
157 3
158
        // addCart form
159
        $forms = [];
160 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...
161 3
            /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
162 3
            $builder = $this->formFactory->createNamedBuilder(
163
                '',
164 3
                AddCartType::class,
165 3
                null,
166 3
                [
167 3
                    'product' => $this->productRepository->findWithSortedClassCategories($Product->getId()),
168
                    'allow_extra_fields' => true,
169 3
                ]
170
            );
171
            $addCartForm = $builder->getForm();
172
173 3
            $forms[$Product->getId()] = $addCartForm->createView();
174
        }
175 3
176
        // 表示件数
177
        $builder = $this->formFactory->createNamedBuilder(
178
            'disp_number',
179 3
            ProductListMaxType::class,
180 3
            null,
181 3
            [
182 3
                'required' => false,
183
                'allow_extra_fields' => true,
184 3
            ]
185 3
        );
186
        if ($request->getMethod() === 'GET') {
187
            $builder->setMethod('GET');
188
        }
189 3
190 3
        $event = new EventArgs(
191
            [
192
                'builder' => $builder,
193 3
            ],
194
            $request
195 3
        );
196
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_DISP, $event);
197 3
198
        $dispNumberForm = $builder->getForm();
199 3
200
        $dispNumberForm->handleRequest($request);
201 3
202
        // ソート順
203 3
        $builder = $this->formFactory->createNamedBuilder(
204
            'orderby',
205
            ProductListOrderByType::class,
206 3
            null,
207 3
            [
208 3
                'required' => false,
209 3
                'allow_extra_fields' => true,
210
            ]
211 3
        );
212 3
        if ($request->getMethod() === 'GET') {
213
            $builder->setMethod('GET');
214
        }
215
216 3
        $event = new EventArgs(
217 3
            [
218
                'builder' => $builder,
219
            ],
220 3
            $request
221
        );
222 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_ORDER, $event);
223
224 3
        $orderByForm = $builder->getForm();
225
226 3
        $orderByForm->handleRequest($request);
227
228 3
        $Category = $searchForm->get('category_id')->getData();
229
230 3
        return [
231
            'subtitle' => $this->getPageTitle($searchData),
232 3
            'pagination' => $pagination,
233
            'search_form' => $searchForm->createView(),
234
            'disp_number_form' => $dispNumberForm->createView(),
235 3
            'order_by_form' => $orderByForm->createView(),
236 3
            'forms' => $forms,
237 3
            'Category' => $Category,
238 3
        ];
239 3
    }
240 3
241 3
    /**
242
     * 商品詳細画面.
243
     *
244
     * @Route("/products/detail/{id}", name="product_detail", methods={"GET"}, requirements={"id" = "\d+"})
245
     * @Template("Product/detail.twig")
246
     * @ParamConverter("Product", options={"repository_method" = "findWithSortedClassCategories"})
247
     *
248
     * @param Request $request
249
     * @param Product $Product
250
     *
251
     * @return array
252
     */
253
    public function detail(Request $request, Product $Product)
254
    {
255
        if (!$this->checkVisibility($Product)) {
256
            throw new NotFoundHttpException();
257
        }
258 11
259
        $builder = $this->formFactory->createNamedBuilder(
260 11
            '',
261
            AddCartType::class,
262
            null,
263
            [
264 11
                'product' => $Product,
265 11
                'id_add_product_id' => false,
266 11
            ]
267 11
        );
268
269 11
        $event = new EventArgs(
270
            [
271
                'builder' => $builder,
272
                'Product' => $Product,
273
            ],
274 11
            $request
275
        );
276 11
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE, $event);
277 11
278
        $is_favorite = false;
279 11
        if ($this->isGranted('ROLE_USER')) {
280
            $Customer = $this->getUser();
281 11
            $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...
282
        }
283 11
284 11
        return [
285 2
            'title' => $this->title,
286 2
            'subtitle' => $Product->getName(),
287
            'form' => $builder->getForm()->createView(),
288
            'Product' => $Product,
289
            'is_favorite' => $is_favorite,
290 11
        ];
291 11
    }
292 11
293 11
    /**
294 11
     * お気に入り追加.
295
     *
296
     * @Route("/products/add_favorite/{id}", name="product_add_favorite", requirements={"id" = "\d+"})
297
     */
298
    public function addFavorite(Request $request, Product $Product)
299
    {
300
        $this->checkVisibility($Product);
301
302
        $event = new EventArgs(
303 3
            [
304
                'Product' => $Product,
305 3
            ],
306
            $request
307 3
        );
308
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE, $event);
309 3
310
        if ($this->isGranted('ROLE_USER')) {
311 3
            $Customer = $this->getUser();
312
            $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...
313 3
            $this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
314
315 3
            $event = new EventArgs(
316 2
                [
317 2
                    'Product' => $Product,
318 2
                ],
319
                $request
320 2
            );
321
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
322 2
323
            return $this->redirectToRoute('product_detail', ['id' => $Product->getId()]);
324 2
        } else {
325
            // 非会員の場合、ログイン画面を表示
326 2
            //  ログイン後の画面遷移先を設定
327
            $this->setLoginTargetPath($this->generateUrl('product_add_favorite', ['id' => $Product->getId()]));
328 2
            $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...
329
330
            $event = new EventArgs(
331
                [
332 1
                    'Product' => $Product,
333 1
                ],
334
                $request
335 1
            );
336
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
337 1
338
            return $this->redirectToRoute('mypage_login');
339 1
        }
340
    }
341 1
342
    /**
343 1
     * カートに追加.
344
     *
345
     * @Route("/products/add_cart/{id}", name="product_add_cart", methods={"POST"}, requirements={"id" = "\d+"})
346
     */
347
    public function addCart(Request $request, Product $Product)
348
    {
349
        // エラーメッセージの配列
350
        $errorMessages = [];
351
        if (!$this->checkVisibility($Product)) {
352
            throw new NotFoundHttpException();
353 37
        }
354
355
        $builder = $this->formFactory->createNamedBuilder(
356 37
            '',
357 37
            AddCartType::class,
358 1
            null,
359
            [
360
                'product' => $Product,
361 36
                'id_add_product_id' => false,
362 36
            ]
363 36
        );
364 36
365
        $event = new EventArgs(
366 36
            [
367
                'builder' => $builder,
368
                'Product' => $Product,
369
            ],
370
            $request
371 36
        );
372
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE, $event);
373 36
374 36
        /* @var $form \Symfony\Component\Form\FormInterface */
375
        $form = $builder->getForm();
376 36
        $form->handleRequest($request);
377
378 36
        if (!$form->isValid()) {
379
            throw new NotFoundHttpException();
380
        }
381 36
382 36
        $addCartData = $form->getData();
383
384 36
        log_info(
385 1
            'カート追加処理開始',
386
            [
387
                'product_id' => $Product->getId(),
388 35
                'product_class_id' => $addCartData['product_class_id'],
389
                'quantity' => $addCartData['quantity'],
390 35
            ]
391 35
        );
392
393 35
        // カートへ追加
394 35
        $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
395 35
396
        // 明細の正規化
397
        $Carts = $this->cartService->getCarts();
398 View Code Duplication
        foreach ($Carts as $Cart) {
399
            $result = $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser()));
400 35
            // 復旧不可のエラーが発生した場合は追加した明細を削除.
401
            if ($result->hasError()) {
402
                $this->cartService->removeProduct($addCartData['product_class_id']);
403 35
                foreach ($result->getErrors() as $error) {
404 35
                    $errorMessages[] = $error->getMessage();
405 35
                }
406
            }
407 35
            foreach ($result->getWarning() as $warning) {
408
                $errorMessages[] = $warning->getMessage();
409
            }
410
        }
411
412
        $this->cartService->save();
413 35
414 35
        log_info(
415
            'カート追加処理完了',
416
            [
417
                'product_id' => $Product->getId(),
418 35
                'product_class_id' => $addCartData['product_class_id'],
419
                'quantity' => $addCartData['quantity'],
420 35
            ]
421 35
        );
422
423 35
        $event = new EventArgs(
424 35
            [
425 35
                'form' => $form,
426
                'Product' => $Product,
427
            ],
428
            $request
429 35
        );
430
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE, $event);
431 35
432 35
        if ($event->getResponse() !== null) {
433
            return $event->getResponse();
434 35
        }
435
436 35
        if ($request->isXmlHttpRequest()) {
437
            // ajaxでのリクエストの場合は結果をjson形式で返す。
438 35
439
            // 初期化
440
            $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...
441
            $messages = [];
442 35
443
            if (empty($errorMessages)) {
444
                // エラーが発生していない場合
445
                $done = true;
446
                array_push($messages, 'カートに追加しました。');
447
            } else {
448
                // エラーが発生している場合
449
                $done = false;
450
                $messages = $errorMessages;
451
            }
452
453
            return $this->json(['done' => $done, 'messages' => $messages]);
454
        } else {
455
            // ajax以外でのリクエストの場合はカート画面へリダイレクト
456
            foreach ($errorMessages as $errorMessage) {
457
                $this->addRequestError($errorMessage);
458
            }
459
460
            return $this->redirectToRoute('cart');
461
        }
462 35
    }
463 5
464
    /**
465
     * ページタイトルの設定
466 35
     *
467
     * @param  null|array $searchData
468
     *
469
     * @return str
470
     */
471
    private function getPageTitle($searchData)
472
    {
473
        if (isset($searchData['name']) && !empty($searchData['name'])) {
474
            return trans('front.product.search_result');
475
        } elseif (isset($searchData['category_id']) && $searchData['category_id']) {
476
            return $searchData['category_id']->getName();
477 3
        } else {
478
            return trans('front.product.all_products');
479 3
        }
480
    }
481 3
482 1
    /**
483
     * 閲覧可能な商品かどうかを判定
484 2
     *
485
     * @param Product $Product
486
     *
487
     * @return boolean 閲覧可能な場合はtrue
488
     */
489
    private function checkVisibility(Product $Product)
490
    {
491
        $is_admin = $this->session->has('_security_admin');
492
493
        // 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
494
        if (!$is_admin) {
495 43
            // 在庫なし商品の非表示オプションが有効な場合.
496
            // if ($this->BaseInfo->isOptionNostockHidden()) {
497 43
            //     if (!$Product->getStockFind()) {
498
            //         return false;
499
            //     }
500 43
            // }
501
            // 公開ステータスでない商品は表示しない.
502
            if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
503
                return false;
504
            }
505
        }
506
507
        return true;
508 43
    }
509
}
510