app/Customize/Controller/ProductController.php line 327

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