<?php
namespace Plugin\Cecplgbase\Controller;
use Eccube\Controller\ProductController as ParentProductController;
use Eccube\Repository\PageRepository;
use Eccube\Entity\BaseInfo;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Entity\Product;
use Eccube\Entity\ProductClass;
use Eccube\Entity\ClassName;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Form\Type\AddCartType;
use Eccube\Form\Type\Master\ProductListMaxType;
use Eccube\Form\Type\Master\ProductListOrderByType;
use Eccube\Form\Type\SearchProductType;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\CustomerFavoriteProductRepository;
use Eccube\Repository\Master\ProductListMaxRepository;
use Eccube\Repository\ProductRepository;
use Eccube\Repository\ClassNameRepository;
use Eccube\Repository\ClassCategoryRepository;
use Eccube\Service\CartService;
use Eccube\Service\PurchaseFlow\PurchaseContext;
use Eccube\Service\PurchaseFlow\PurchaseFlow;
use Knp\Bundle\PaginatorBundle\Pagination\SlidingPagination;
use Knp\Component\Pager\Paginator;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Plugin\Cecplgbase\Repository\ConfigRepository;
class ProductController extends ParentProductController
{
/**
* @var PurchaseFlow
*/
protected $purchaseFlow;
/**
* @var CustomerFavoriteProductRepository
*/
protected $customerFavoriteProductRepository;
/**
* @var CartService
*/
protected $cartService;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var BaseInfo
*/
protected $BaseInfo;
/**
* @var AuthenticationUtils
*/
protected $helper;
/**
* @var ProductListMaxRepository
*/
protected $productListMaxRepository;
/**
* @var PageRepository
*/
protected $pageRepository;
/**
* @var ClassNameRepository
*/
protected $classNameRepository;
/**
* @var ClassCategoryRepository
*/
protected $classCategoryRepository;
/**
* @var ConfigRepository
*/
protected $configRepository;
private $title = '';
/**
* ProductController constructor.
*
* @param PurchaseFlow $cartPurchaseFlow
* @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
* @param CartService $cartService
* @param ProductRepository $productRepository
* @param BaseInfoRepository $baseInfoRepository
* @param AuthenticationUtils $helper
* @param ProductListMaxRepository $productListMaxRepository
* @param PageRepository $pageRepository
* @param ClassNameRepository $classNameRepository
* @param ClassCategoryRepository $classCategoryRepository
* @param ConfigRepository $configRepository
*/
public function __construct(
PurchaseFlow $cartPurchaseFlow,
CustomerFavoriteProductRepository $customerFavoriteProductRepository,
CartService $cartService,
ProductRepository $productRepository,
BaseInfoRepository $baseInfoRepository,
AuthenticationUtils $helper,
ProductListMaxRepository $productListMaxRepository,
PageRepository $pageRepository,
ClassNameRepository $classNameRepository,
ClassCategoryRepository $classCategoryRepository,
ConfigRepository $configRepository
) {
$this->purchaseFlow = $cartPurchaseFlow;
$this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
$this->cartService = $cartService;
$this->productRepository = $productRepository;
$this->BaseInfo = $baseInfoRepository->get();
$this->helper = $helper;
$this->productListMaxRepository = $productListMaxRepository;
$this->pageRepository = $pageRepository;
$this->classNameRepository = $classNameRepository;
$this->classCategoryRepository = $classCategoryRepository;
$this->configRepository = $configRepository->get();
}
/**
* 商品一覧画面.
*
* @Route("/products/list", name="product_list")
* @Template("Product/list.twig")
*/
public function index(Request $request, Paginator $paginator)
{
$arrRet = parent::index($request, $paginator);
//タグの情報を作成
$search_form=$arrRet['search_form'];
$arrVars = $search_form->vars;
$arrValues = $arrVars['value'];
$arrRet['Tag'] = $arrValues['tag_id'];
return $arrRet;
}
/**
* 商品詳細画面.
*
* @Route("/products/detail/{id}", name="product_detail", methods={"GET"}, requirements={"id" = "\d+"})
* @Template("Product/detail.twig")
* @ParamConverter("Product", options={"repository_method" = "findWithSortedClassCategories"})
*
* @param Request $request
* @param Product $Product
*
* @return array
*/
public function detail(Request $request, Product $Product)
{
//親のdetailで作成される変数を用意する。titleとsub_titleは使わない
$arrRarent = parent::detail($request,$Product);
$form = $arrRarent['form'];
$Product = $arrRarent['Product'];
$is_favorite = $arrRarent['is_favorite'];
// 規格名1/2から組み合わせを生成し, DBから取得した商品規格とマージする.
// Cecplgbase/Resource/template/sample_classcategory_table.twigのコードを商品詳細ページで使うための変数作成
if(isset($form['classcategory_id1'])){
$ClassName1 = $this->classNameRepository->findOneBy(['name'=>$Product->getClassName1()]);
$ClassName2 = $this->classNameRepository->findOneBy(['name'=>$Product->getClassName2()]);
$ProductClasses = $Product->getProductClasses();
$ProductClasses = $this->mergeProductClasses(
$this->createProductClasses($ClassName1, $ClassName2),
$ProductClasses);
}
//ページのタイトル変更用
$Page = $this->pageRepository
->findOneBy([
'id' => 3,
]);
if(!empty($Product->getAuthor())) $Page->setAuthor($Product->getAuthor());
if(!empty($Product->getDescription())) $Page->setDescription($Product->getDescription());
if(!empty($Product->getKeyword())) $Page->setKeyword($Product->getKeyword());
if(!empty($Product->getMetaRobots())) $Page->setMetaRobots($Product->getMetaRobots());
if(!empty($Product->getMetaTags())) $Page->setMetaTags($Product->getMetaTags());
if(!empty($Product->getTitle())){
$subtitle=$Product->getTitle();
}
else{
$subtitle=$Product->getName();
}
//「関連カテゴリ」表示で、親カテを重複して表示させない
$arrTemp=array();
foreach($Product->getProductCategories() as $ProductCategory){
if($ProductCategory->getCategory()->getParent()){
$arrTemp[]=$ProductCategory->getCategory()->getParent()->getId();
};
}
foreach($Product->getProductCategories() as $key=>$value){
if(in_array($value['category_id'],$arrTemp)){
unset($Product->getProductCategories()[$key]);
}
}
return [
'Page' => $Page,
'subtitle' => $subtitle,
'form' => $form,
'Product' => $Product,
'is_favorite' => $is_favorite,
'ProductClasses' => $ProductClasses??NULL
];// オリジナルはここで'title' => $this->titleで空の値をパスしてますが、そのラインを削除して、他ページと同様、ページ管理の値がtitleに入るようにしてます。
}
/**
* カートに追加.
*
* @Route("/products/add_cart/{id}", name="product_add_cart", methods={"POST"}, requirements={"id" = "\d+"})
*/
public function addCart(Request $request, Product $Product)
{
// エラーメッセージの配列
$errorMessages = [];
if (!$this->checkVisibility($Product)) {
throw new NotFoundHttpException();
}
$builder = $this->formFactory->createNamedBuilder(
'',
AddCartType::class,
null,
[
'product' => $Product,
'id_add_product_id' => false,
]
);
$event = new EventArgs(
[
'builder' => $builder,
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE, $event);
/* @var $form \Symfony\Component\Form\FormInterface */
$form = $builder->getForm();
$form->handleRequest($request);
if (!$form->isValid()) {
throw new NotFoundHttpException();
}
$addCartData = $form->getData();
log_info(
'カート追加処理開始',
[
'product_id' => $Product->getId(),
'product_class_id' => $addCartData['product_class_id'],
'quantity' => $addCartData['quantity'],
]
);
// カートへ追加, シンプル規格ここを編集 by toguchi 2022-09-03
if($this->configRepository->getSimpleClassOn() && count($Product->getSimpleClassNames())>0 ){
$SimpleClass = [];
foreach($Product->getSimpleClassNames() as $SimpleClassName){
$SimpleClass[$SimpleClassName->getId()] = $form->get('simple_class_'.$SimpleClassName->getId())->getData();
}
$this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity'], $SimpleClass);
}
else{
$this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
}
// 明細の正規化
$Carts = $this->cartService->getCarts();
foreach ($Carts as $Cart) {
$result = $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser()));
// 復旧不可のエラーが発生した場合は追加した明細を削除.
if ($result->hasError()) {
$this->cartService->removeProduct($addCartData['product_class_id']);
foreach ($result->getErrors() as $error) {
$errorMessages[] = $error->getMessage();
}
}
foreach ($result->getWarning() as $warning) {
$errorMessages[] = $warning->getMessage();
}
}
$this->cartService->save();
log_info(
'カート追加処理完了',
[
'product_id' => $Product->getId(),
'product_class_id' => $addCartData['product_class_id'],
'quantity' => $addCartData['quantity'],
]
);
$event = new EventArgs(
[
'form' => $form,
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE, $event);
if ($event->getResponse() !== null) {
return $event->getResponse();
}
if ($request->isXmlHttpRequest()) {
// ajaxでのリクエストの場合は結果をjson形式で返す。
// 初期化
$done = null;
$messages = [];
if (empty($errorMessages)) {
// エラーが発生していない場合
$done = true;
array_push($messages, trans('front.product.add_cart_complete'));
} else {
// エラーが発生している場合
$done = false;
$messages = $errorMessages;
}
return $this->json(['done' => $done, 'messages' => $messages]);
} else {
// ajax以外でのリクエストの場合はカート画面へリダイレクト
foreach ($errorMessages as $errorMessage) {
$this->addRequestError($errorMessage);
}
return $this->redirectToRoute('cart');
}
}
/**
* ページタイトルの設定
*
* @param null|array $searchData
*
* @return str
*/
protected function getPageTitle($searchData)
{
//タグの情報を追加して、検索結果のタイトルを変更
if (isset($searchData['name']) && !empty($searchData['name'])) {
return '「'.$searchData['name'].'」の'.trans('front.product.search_result');
} elseif (isset($searchData['category_id']) && $searchData['category_id']) {
return $searchData['category_id']->getName();
} elseif (isset($searchData['tag_id']) && $searchData['tag_id']) {
return $searchData['tag_id']->getName();
} else {
return trans('front.product.all_products');
}
}
/**
* 規格名1/2から, 商品規格の組み合わせを生成する. copied from src/Eccube/Controller/Admin/Product/ProductClassController.php
*
* @param ClassName $ClassName1
* @param ClassName|null $ClassName2
*
* @return array|ProductClass[]
*/
protected function createProductClasses(ClassName $ClassName1, ClassName $ClassName2 = null)
{
$ProductClasses = [];
$ClassCategories1 = $this->classCategoryRepository->findBy(['ClassName' => $ClassName1], ['sort_no' => 'DESC']);
$ClassCategories2 = [];
if ($ClassName2) {
$ClassCategories2 = $this->classCategoryRepository->findBy(['ClassName' => $ClassName2],['sort_no' => 'DESC']);
}
foreach ($ClassCategories1 as $ClassCategory1) {
// 規格1のみ
if (!$ClassName2) {
$ProductClass = new ProductClass();
$ProductClass->setClassCategory1($ClassCategory1);
$ProductClasses[] = $ProductClass;
continue;
}
// 規格1/2
foreach ($ClassCategories2 as $ClassCategory2) {
$ProductClass = new ProductClass();
$ProductClass->setClassCategory1($ClassCategory1);
$ProductClass->setClassCategory2($ClassCategory2);
$ProductClasses[] = $ProductClass;
}
}
return $ProductClasses;
}
/**
* 商品規格の配列をマージする. copied from src/Eccube/Controller/Admin/Product/ProductClassController.php
*
* @param $ProductClassesForMatrix
* @param $ProductClasses
*
* @return array|ProductClass[]
*/
protected function mergeProductClasses($ProductClassesForMatrix, $ProductClasses)
{
$mergedProductClasses = [];
foreach ($ProductClassesForMatrix as $pcfm) {
foreach ($ProductClasses as $pc) {
if ($pcfm->getClassCategory1()->getId() === $pc->getClassCategory1()->getId()) {
$cc2fm = $pcfm->getClassCategory2();
$cc2 = $pc->getClassCategory2();
if (null === $cc2fm && null === $cc2) {
$mergedProductClasses[] = $pc;
continue 2;
}
if ($cc2fm && $cc2 && $cc2fm->getId() === $cc2->getId()) {
$mergedProductClasses[] = $pc;
continue 2;
}
}
}
$mergedProductClasses[] = $pcfm;
}
return $mergedProductClasses;
}
}