src/AppBundle/Controller/ProductController.php line 217

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace AppBundle\Controller;
  15. use AppBundle\Model\Product\AbstractProduct;
  16. use AppBundle\Model\Product\AccessoryPart;
  17. use AppBundle\Model\Product\Car;
  18. use AppBundle\Model\Product\Category;
  19. use AppBundle\Services\SegmentTrackingHelperService;
  20. use AppBundle\Website\LinkGenerator\ProductLinkGenerator;
  21. use AppBundle\Website\Navigation\BreadcrumbHelperService;
  22. use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
  23. use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\Helper;
  24. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\DefaultMysql;
  25. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ElasticSearch\AbstractElasticSearch;
  26. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ProductListInterface;
  27. use Pimcore\Config;
  28. use Pimcore\Model\DataObject\AbstractObject;
  29. use Pimcore\Model\DataObject\Concrete;
  30. use Pimcore\Model\DataObject\Data\UrlSlug;
  31. use Pimcore\Model\DataObject\FilterDefinition;
  32. use Pimcore\Templating\Helper\HeadTitle;
  33. use Pimcore\Templating\Model\ViewModel;
  34. use Pimcore\Translation\Translator;
  35. use Symfony\Component\HttpFoundation\Request;
  36. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  37. use Symfony\Component\Routing\Annotation\Route;
  38. use Zend\Paginator\Paginator;
  39. class ProductController extends BaseController
  40. {
  41.     /**
  42.      * @param Request $request
  43.      * @param AbstractObject $object
  44.      * @param UrlSlug $urlSlug
  45.      * @return \Symfony\Component\HttpFoundation\Response
  46.      */
  47.     public function productDetailSlugAction(Request $requestAbstractObject $objectUrlSlug $urlSlug) {
  48.         return $this->forward('AppBundle\Controller\ProductController::detailAction', ['product' => $object]);
  49.     }
  50.     /**
  51.      * @Route("/shop/{path}{productname}~p{product}", name="shop-detail", defaults={"path"=""}, requirements={"path"=".*?", "productname"="[\w-]+", "product"="\d+"})
  52.      *
  53.      * @param Request $request
  54.      * @param HeadTitle $headTitleHelper
  55.      * @param BreadcrumbHelperService $breadcrumbHelperService
  56.      * @param Factory $ecommerceFactory
  57.      * @param SegmentTrackingHelperService $segmentTrackingHelperService
  58.      * @param Concrete $product built-in parameter conversion, please see https://github.com/pimcore/pimcore/pull/5554
  59.      *
  60.      * @return \Symfony\Component\HttpFoundation\Response
  61.      *
  62.      * @throws \Exception
  63.      */
  64.     public function detailAction(
  65.         Request $request,
  66.         HeadTitle $headTitleHelper,
  67.         BreadcrumbHelperService $breadcrumbHelperService,
  68.         Factory $ecommerceFactory,
  69.         SegmentTrackingHelperService $segmentTrackingHelperService,
  70.         Concrete $product,
  71.         ProductLinkGenerator $productLinkGenerator
  72.     )
  73.     {
  74.         if (!(
  75.                 $product && ($product->isPublished() && (($product instanceof Car && $product->getObjectType() == Car::OBJECT_TYPE_ACTUAL_CAR) || $product instanceof AccessoryPart) || $this->verifyPreviewRequest($request$product))
  76.             )
  77.         ) {
  78.             throw new NotFoundHttpException('Product not found.');
  79.         }
  80.         //redirect to main url
  81.         $generatorUrl $productLinkGenerator->generate($product);
  82.         if($generatorUrl != $request->getPathInfo()) {
  83.             $queryString $request->getQueryString();
  84.             return $this->redirect($generatorUrl . ($queryString '?' $queryString ''));
  85.         }
  86.         $breadcrumbHelperService->enrichProductDetailPage($product);
  87.         $headTitleHelper($product->getOSName());
  88.         $paramBag $this->view->getAllParameters();
  89.         $paramBag['product'] = $product;
  90.         //track segments for personalization
  91.         $segmentTrackingHelperService->trackSegmentsForProduct($product);
  92.         $trackingManager $ecommerceFactory->getTrackingManager();
  93.         $trackingManager->trackProductView($product);
  94.         if ($product instanceof Car) {
  95.             foreach ($product->getAccessories() as $accessory) {
  96.                 $trackingManager->trackProductImpression($accessory'crosssells');
  97.             }
  98.             return $this->render('product/detail.html.twig'$paramBag);
  99.         } elseif ($product instanceof AccessoryPart) {
  100.             // get all compatible products
  101.             $productList $ecommerceFactory->getIndexService()->getProductListForCurrentTenant();
  102.             $productList->setVariantMode(ProductListInterface::VARIANT_MODE_VARIANTS_ONLY);
  103.             if($productList instanceof DefaultMysql) {
  104.                 $productList->addCondition('o_id IN (' implode(','$product->getCompatibleToProductIds()) . ')''o_id');
  105.             } else if($productList instanceof AbstractElasticSearch) {
  106.                 $productList->addCondition(['terms' => ['system.o_id' => $product->getCompatibleToProductIds()]], 'o_id');
  107.             }
  108.             foreach($productList as $compatibleProduct) {
  109.                 $trackingManager->trackProductImpression($compatibleProduct'crosssells');
  110.             }
  111.             $paramBag['compatibleTo'] = $productList;
  112.             return $this->render('product/detail_accessory.html.twig'$paramBag);
  113.         }
  114.     }
  115.     /**
  116.      * @Route("/shop/{path}{categoryname}~c{category}", name="shop-category", defaults={"path"=""}, requirements={"path"=".*?", "categoryname"="[\w-]+", "category"="\d+"})
  117.      *
  118.      * @param Request $request
  119.      * @param HeadTitle $headTitleHelper
  120.      * @param BreadcrumbHelperService $breadcrumbHelperService
  121.      * @param Factory $ecommerceFactory
  122.      * @param SegmentTrackingHelperService $segmentTrackingHelperService
  123.      *
  124.      * @return array|\Symfony\Component\HttpFoundation\Response
  125.      */
  126.     public function listingAction(Request $requestHeadTitle $headTitleHelperBreadcrumbHelperService $breadcrumbHelperServiceFactory $ecommerceFactorySegmentTrackingHelperService $segmentTrackingHelperService)
  127.     {
  128.         $viewModel = new ViewModel();
  129.         $params array_merge($request->query->all(), $request->attributes->all());
  130.         //needed to make sure category filter filters for active category
  131.         $params['parentCategoryIds'] = $params['category'] ?? null;
  132.         $category Category::getById($params['category'] ?? null);
  133.         $viewModel->category $category;
  134.         if ($category) {
  135.             $headTitleHelper($category->getName());
  136.             $breadcrumbHelperService->enrichCategoryPage($category);
  137.         }
  138.         $indexService $ecommerceFactory->getIndexService();
  139.         $productListing $indexService->getProductListForCurrentTenant();
  140.         $productListing->setVariantMode(ProductListInterface::VARIANT_MODE_VARIANTS_ONLY);
  141.         $viewModel->productListing $productListing;
  142.         // load current filter
  143.         if ($category) {
  144.             $filterDefinition $category->getFilterdefinition();
  145.             //track segments for personalization
  146.             $segmentTrackingHelperService->trackSegmentsForCategory($category);
  147.             $trackingManager $ecommerceFactory->getTrackingManager();
  148.             $trackingManager->trackCategoryPageView($category->getName(), null);
  149.         }
  150.         if ($request->get('filterdefinition') instanceof FilterDefinition) {
  151.             $filterDefinition $request->get('filterdefinition');
  152.         }
  153.         if (empty($filterDefinition)) {
  154.             $filterDefinition Config::getWebsiteConfig()->get('fallbackFilterdefinition');
  155.         }
  156.         $filterService $ecommerceFactory->getFilterService();
  157.         Helper::setupProductList($filterDefinition$productListing$params$viewModel$filterServicetrue);
  158.         $viewModel->filterService $filterService;
  159.         $viewModel->filterDefinition $filterDefinition;
  160.         // init pagination
  161.         $paginator = new Paginator($productListing);
  162.         $paginator->setCurrentPageNumber($request->get('page'));
  163.         $paginator->setItemCountPerPage($filterDefinition->getPageLimit());
  164.         $paginator->setPageRange(5);
  165.         $viewModel->results $paginator;
  166.         $viewModel->paginationVariables $paginator->getPages('Sliding');
  167.         if ($request->attributes->get('noLayout')) {
  168.             return $this->render('/product/listing_content.html.twig'array_merge($this->view->getAllParameters(), $viewModel->getAllParameters()));
  169.         }
  170.         // track product impressions
  171.         $trackingManager $ecommerceFactory->getTrackingManager();
  172.         foreach ($paginator as $product) {
  173.             $trackingManager->trackProductImpression($product'grid');
  174.         }
  175.         return $viewModel->getAllParameters();
  176.     }
  177.     /**
  178.      * @param Request $request
  179.      * @param Factory $ecommerceFactory
  180.      *
  181.      * @return \Symfony\Component\HttpFoundation\Response
  182.      */
  183.     public function productTeaserAction(Request $requestFactory $ecommerceFactory)
  184.     {
  185.         $paramsBag = [];
  186.         if ($request->get('type') == 'object') {
  187.             AbstractObject::setGetInheritedValues(true);
  188.             $product AbstractProduct::getById($request->get('id'));
  189.             $paramsBag['product'] = $product;
  190.             //track product impression
  191.             $trackingManager $ecommerceFactory->getTrackingManager();
  192.             $trackingManager->trackProductImpression($product'teaser');
  193.             return $this->render('/product/product_teaser.html.twig'$paramsBag);
  194.         }
  195.         throw new NotFoundHttpException('Product not found.');
  196.     }
  197.     /**
  198.      * @Route("/search", name="search")
  199.      *
  200.      * @param Request $request
  201.      * @param Factory $ecommerceFactory
  202.      * @param ProductLinkGenerator $productLinkGenerator
  203.      * @param Translator $translator
  204.      * @param BreadcrumbHelperService $breadcrumbHelperService
  205.      * @param HeadTitle $headTitleHelper
  206.      *
  207.      * @return array|\Symfony\Component\HttpFoundation\JsonResponse
  208.      */
  209.     public function searchAction(Request $requestFactory $ecommerceFactoryProductLinkGenerator $productLinkGeneratorTranslator $translatorBreadcrumbHelperService $breadcrumbHelperServiceHeadTitle $headTitleHelper)
  210.     {
  211.         $params $request->query->all();
  212.         $viewModel = new ViewModel();
  213.         $viewModel->category Category::getById($params['category'] ?? null);
  214.         $indexService $ecommerceFactory->getIndexService();
  215.         $productListing $indexService->getProductListForCurrentTenant();
  216.         $productListing->setVariantMode(ProductListInterface::VARIANT_MODE_VARIANTS_ONLY);
  217.         $term strip_tags($request->get('term'));
  218.         if($productListing instanceof AbstractElasticSearch) {
  219.             // simple elastic search query - uses multi-match query on all defined search_attributes
  220. //            $productListing->addQueryCondition($term);
  221.             //sample for a more specific elastic search query - not considers search_attributes but provides full flexibility
  222.             // this query weights cars more that accessories
  223.             $query = [
  224.                 'function_score' => [
  225.                     'query' => [
  226.                         'multi_match' => [
  227.                             "query" => $term,
  228.                             "type" => "cross_fields",
  229.                             "operator" => "and",
  230.                             "fields" => [
  231.                                 "attributes.name^4",
  232.                                 "attributes.name.analyzed",
  233.                                 "attributes.name.analyzed_ngram",
  234.                                 "attributes.manufacturer_name^3",
  235.                                 "attributes.manufacturer_name.analyzed",
  236.                                 "attributes.manufacturer_name.analyzed_ngram",
  237.                                 "attributes.color",
  238.                                 "attributes.color.analyzed",
  239.                                 "attributes.color.analyzed_ngram",
  240.                                 "attributes.carClass",
  241.                                 "attributes.carClass.analyzed",
  242.                                 "attributes.carClass.analyzed_ngram"
  243.                             ]
  244.                         ]
  245.                     ],
  246.                     'functions' => [
  247.                         [
  248.                             'filter' => ['match' => ['system.o_classId' => 'AP']],
  249.                             'weight' => 1
  250.                         ],
  251.                         [
  252.                             'filter' => ['match' => ['system.o_classId' => 'CAR']],
  253.                             'weight' => 2
  254.                         ]
  255.                     ],
  256.                     'boost_mode' => 'multiply'
  257.                 ]
  258.             ];
  259.             $productListing->addQueryCondition($query'searchTerm');
  260.         } else {
  261.             //default mysql search query condition - would also work for elastic search in that way
  262.             $term trim(preg_replace('/\s+/'' '$term));
  263.             if (!empty($term)) {
  264.                 foreach (explode(' '$term) as $t) {
  265.                     $productListing->addQueryCondition($t);
  266.                 }
  267.             }
  268.         }
  269.         if (isset($params['autocomplete'])) {
  270.             $resultset = [];
  271.             $productListing->setLimit(10);
  272.             foreach ($productListing as $product) {
  273.                 $result['href'] = $productLinkGenerator->generateWithMockup($product, []);
  274.                 if ($product instanceof Car) {
  275.                     $result['product'] = $product->getOSName() . ' ' $product->getColor()[0] . ', ' $product->getCarClass();
  276.                 } else {
  277.                     $result['product'] = $product->getOSName();
  278.                 }
  279.                 $resultset[] = $result;
  280.             }
  281.             return $this->json($resultset);
  282.         }
  283.         $filterDefinition $viewModel->filterDefinition Config::getWebsiteConfig()->get('fallbackFilterdefinition');
  284.         // create and init filter service
  285.         $filterService Factory::getInstance()->getFilterService();
  286.         Helper::setupProductList($filterDefinition$productListing$params$viewModel$filterServicetrue);
  287.         $viewModel->filterService $filterService;
  288.         $viewModel->products $productListing;
  289.         // init pagination
  290.         $paginator = new Paginator($productListing);
  291.         $paginator->setCurrentPageNumber($request->get('page'));
  292.         $paginator->setItemCountPerPage($filterDefinition->getPageLimit());
  293.         $paginator->setPageRange(5);
  294.         $viewModel->results $paginator;
  295.         $viewModel->paginationVariables $paginator->getPages('Sliding');
  296.         $trackingManager $ecommerceFactory->getTrackingManager();
  297.         foreach ($paginator as $product) {
  298.             $trackingManager->trackProductImpression($product'search-results');
  299.         }
  300.         //breadcrumbs
  301.         $placeholder $this->get('pimcore.templating.view_helper.placeholder');
  302.         $placeholder('addBreadcrumb')->append([
  303.             'parentId' => $this->document->getId(),
  304.             'id' => 'search-result',
  305.             'label' => $translator->trans('shop.search-result', [$term])
  306.         ]);
  307.         $viewModel->language $request->getLocale();
  308.         $viewModel->term $term;
  309.         $breadcrumbHelperService->enrichGenericDynamicPage($translator->trans('shop.search-result', [$term]));
  310.         $headTitleHelper($translator->trans('shop.search-result', [$term]));
  311.         return $viewModel->getAllParameters();
  312.     }
  313. }