Completed
Push — 4.0 ( b48f64...137622 )
by chihiro
20:21 queued 10s
created

src/Eccube/Controller/ProductController.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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