src/Controller/ProductController.php line 231

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Model\DataObject\Decor;
  4. use App\Model\DataObject\VirtualProduct;
  5. use App\Templating\Helper\ConfigHelper;
  6. use App\Tools\IndexHelper;
  7. use App\Tools\LocaleHelper;
  8. use App\Tools\SelectOptionsHelper;
  9. use App\Twig\LinkGenerator;
  10. use Elements\Bundle\SeoHelperBundle\Templating\Helper\Robots;
  11. use Elements\Bundle\TrackingBundle\Tracking\TrackingManager;
  12. use Knp\Component\Pager\PaginatorInterface;
  13. use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
  14. use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;
  15. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ProductListInterface;
  16. use Pimcore\Log\ApplicationLogger;
  17. use Pimcore\Model\DataObject;
  18. use Pimcore\Model\DataObject\Application;
  19. use Pimcore\Model\DataObject\ApplicationArea;
  20. use Pimcore\Model\DataObject\Product;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. class ProductController extends AbstractController
  26. {
  27.     protected const STEP_TO_FILTER = [
  28.         'selection1' => 'applicationAreas',
  29.         'selection2' => 'allApplications',
  30.         'selection3' => 'decorGroup',
  31.         'selection4' => 'allCharacteristics',
  32.     ];
  33.     protected const STEP_TO_TRACKING_PARAM = [
  34.         'selection1' => 'location',
  35.         'selection2' => 'application',
  36.         'selection3' => 'decor_group',
  37.         'selection4' => 'features',
  38.     ];
  39.     protected DataObject\SiteConfig $siteConfig;
  40.     protected array $applicationAreaMapping = [];
  41.     public function __construct(ApplicationLogger $applicationLoggerConfigHelper $configHelper)
  42.     {
  43.         $this->siteConfig $configHelper->getSiteConfig();
  44.         $this->applicationAreaMapping = [
  45.             $this->siteConfig->getInteriorArea()?->getId() => 'interior',
  46.             $this->siteConfig->getExteriorArea()?->getId() => 'exterior',
  47.             $this->siteConfig->getUniveralArea()?->getId() => 'universal',
  48.         ];
  49.         parent::__construct($applicationLogger);
  50.     }
  51.     public function overviewAction(Request $requestPaginatorInterface $paginatorFactory $factoryListHelper $listHelper) {
  52.         $templateParams = [];
  53.         $params array_merge($request->query->all(), $request->request->all());
  54.         $filterDefinition $this->getDocumentEditable('relation''filterDefinition')->getElement();
  55.         $filterService $factory->getFilterService();
  56.         if (empty($filterDefinition)) {
  57.             $filterDefinition \Pimcore\Config::getWebsiteConfig()->fallbackFilterdefinition;
  58.         }
  59.         $templateParams['filterDefinition'] = $filterDefinition;
  60.         //product listing for filter
  61.         $productListing $factory->getIndexService()->getProductListForCurrentTenant();
  62.         $productListing->setVariantMode(ProductListInterface::VARIANT_MODE_HIDE);
  63.         $productListing->addCondition(IndexHelper::INDEX_O_CLASS_ID ' = "VirtualProduct"');
  64.         $listHelper->setupProductList($filterDefinition$productListing$params$filterServicetrue);
  65.         $templateParams['productListing'] = $productListing;
  66.         // product listing
  67.         $products $factory->getIndexService()->getProductListForCurrentTenant();
  68.         $products->setVariantMode(ProductListInterface::VARIANT_MODE_HIDE);
  69.         $products->addCondition(IndexHelper::INDEX_O_CLASS_ID ' = "VirtualProduct"');
  70.         // apply filters
  71.         $listHelper->setupProductList($filterDefinition$products$params$filterServicetrue);
  72.         $templateParams['filterService'] = $filterService;
  73.         $templateParams['currentFilter'] = $params['currentFilter'];
  74.         // paginate
  75.         $paging $paginator->paginate($products$request->get('page'1), $filterDefinition->getPageLimit());
  76.         $templateParams['products'] = $paging;
  77.         $trackingManager $factory->getTrackingManager();
  78.         foreach ($paging as $product) {
  79.             $trackingManager->trackProductImpression($product);
  80.         }
  81.         if ($request->isXmlHttpRequest()) {
  82.             return $this->json([
  83.                 'success' => true,
  84.                 'html' => $this->renderView('product/includes/product-grid-container.html.twig'$templateParams)
  85.             ]);
  86.         }
  87.         return $this->renderTemplate('product/overview.html.twig'$templateParams);
  88.     }
  89.     public function productFinderAction(Request $requestSessionInterface $session): Response
  90.     {
  91.         $step = (int)$request->get('step'1);
  92.         while ((($request->get('back'false) && $step 1) || $step 4) && $this->document->getEditable('options' $step)?->isEmpty()) {
  93.             if ($request->get('back'false)) {
  94.                 $step--;
  95.             } else {
  96.                 $step++;
  97.             }
  98.         }
  99.         $selection $session->get('selection', [
  100.             'selection1' => [],
  101.             'selection2' => [],
  102.             'selection3' => [],
  103.             'selection4' => [],
  104.         ]);
  105.         $options $this->document->getEditable('options' $step)?->getValue();
  106.         $returnArray = [
  107.             'step' => $step,
  108.             'ajax' => $request->get('ajax'false),
  109.             'back' => $request->get('back'false),
  110.             'selection' => $selection,
  111.             'options' => $options,
  112.         ];
  113.         if ($request->isMethod('POST')) {
  114.             $selection['selection' $step] = $this->getSelection($request->get('selection' $step, []));
  115.             $session->set('selection'$selection);
  116.             if ($request->get('step') < 4) {
  117.                 $step++;
  118.                 while ((($request->get('back'false) && $step 1) || $step 4) && $this->document->getEditable('options' $step)?->isEmpty()) {
  119.                     if ($request->get('back'false)) {
  120.                         $step--;
  121.                     } else {
  122.                         $step++;
  123.                     }
  124.                 }
  125.                 $returnArray['step'] = $step;
  126.                 $returnArray['selection'] = $selection;
  127.                 $options $this->document->getEditable('options' $step)?->getValue();
  128.                 if ($step === && !empty(array_filter($selection['selection1']))) {
  129.                     $selectedApplicationAreas array_intersect_key($this->applicationAreaMapping$selection['selection1']);
  130.                     $options array_filter($options, static function (Application $o) use ($selectedApplicationAreas) {
  131.                         return in_array($o->getApplicationArea(), $selectedApplicationAreastrue);
  132.                     });
  133.                 }
  134.                 //NUR beim letzten Schritt das "responseTrackingData" mit den Daten aus dem "$gtm"-Objekt zur json response dazu geben
  135.                 $returnArray['options'] = $options;
  136.                 return $this->json([
  137.                     'success' => true,
  138.                     'html' => $this->renderTemplate('product/includes/productfinder-form.html.twig'$returnArray)->getContent(),
  139.                 ], 200, ['X-Robots-Tag' => 'noindex']);
  140.             }
  141.             if ($this->siteConfig && $this->siteConfig->getProductOverview()) {
  142.                 $params = [];
  143.                 $trackingParams = ["event" => "product_finder_finished"];
  144.                 foreach ($selection as $step => $values) {
  145.                     if (array_key_exists($stepself::STEP_TO_TRACKING_PARAM)) {
  146.                         $trackingParams[self::STEP_TO_TRACKING_PARAM[$step]] = implode(', '$values);
  147.                     }
  148.                     if (array_key_exists($stepself::STEP_TO_FILTER)) {
  149.                         foreach (array_keys($values) as $id) {
  150.                             $params[self::STEP_TO_FILTER[$step]][] = $id;
  151.                         }
  152.                     }
  153.                 }
  154.                 $this->addFlash('tracking'$trackingParams);
  155.                 $query http_build_query($params);
  156.                 $query preg_replace('/%5B\d+%5D/simU''%5B%5D'$query);
  157.                 $session->clear();
  158.                 return $this->redirect($this->siteConfig->getProductOverview()->getFullPath() . '?' $query '#grid');
  159.             }
  160.         }
  161.         if ($step === && !empty(array_filter($selection['selection1']))) {
  162.             $selectedApplicationAreas array_intersect_key($this->applicationAreaMapping$selection['selection1']);
  163.             $options array_filter($options, static function (Application $o) use ($selectedApplicationAreas) {
  164.                 return in_array($o->getApplicationArea(), $selectedApplicationAreastrue);
  165.             });
  166.             $returnArray['options'] = $options;
  167.         }
  168.         if ($request->get('ajax')) {
  169.             return $this->json([
  170.                 'success' => true,
  171.                 'html' => $this->renderTemplate('product/includes/productfinder-form.html.twig'$returnArray)->getContent()
  172.             ], 200, ['X-Robots-Tag' => 'noindex']);
  173.         }
  174.         return $this->renderTemplate('product/productfinder.html.twig'$returnArray);
  175.     }
  176.     /**
  177.      * @Route ("/product-finder-banner", name="product_finder_banner")
  178.      * @param Request $request
  179.      * @return \Symfony\Component\HttpFoundation\RedirectResponse
  180.      */
  181.     public function productFinderBanner(Request $requestSessionInterface $session)
  182.     {
  183.         $selection $session->get('selection', [
  184.             'selection1' => [],
  185.             'selection2' => [],
  186.             'selection3' => [],
  187.             'selection4' => [],
  188.         ]);
  189.         $selection['selection1'] = $this->getSelection($request->get('selection1', []));
  190.         $session->set('selection'$selection);
  191.         $page $this->siteConfig?->getProductFinder(LocaleHelper::LANG_DE);
  192.         return $this->redirect($page?->getFullPath().'?step=2');
  193.     }
  194.     public function materialGroupOverviewAction(Request $request) {
  195.         return $this->renderTemplate('product/material-group-overview.html.twig');
  196.     }
  197.     public function detailAction(Request $requestFactory $factoryLinkGenerator $linkGenerator): Response
  198.     {
  199.         $product $this->getValidDetailObject($requestVirtualProduct::class);
  200.         if ($request->getPathInfo() !== $linkGenerator->generate($product)) {
  201.             return $this->redirect($linkGenerator->generate($product));
  202.         }
  203.         $trackingManager $factory->getTrackingManager();
  204.         $trackingManager->trackProductView($product);
  205.         return $this->renderTemplate('product/detail.html.twig', [
  206.             'product' => $product,
  207.             'similarProducts' => $this->getSimilarProducts($product$factory)
  208.         ]);
  209.     }
  210.     /**
  211.      * @Route("/{_locale}/product-gallery-images/{product}/{page}", name="_product_gallery_images")
  212.      */
  213.     public function getGalleryImages(VirtualProduct $product$page) {
  214.         $from * ($page 1);
  215.         $to $from 3;
  216.         return $this->json([
  217.             'success' => true,
  218.             'html' => $this->renderView('product/includes/image-gallery.html.twig', ['images' => $product->getGalleryItems($from$to), 'product' => $product'containerId' => 'product-gallery-' $product->getId(), 'page' => $page])
  219.         ]);
  220.     }
  221.     protected function getSelection(array $ids): array
  222.     {
  223.         $selection = [];
  224.         foreach ($ids as $id) {
  225.             $object DataObject::getById($id);
  226.             if ($object && method_exists($object'getTitle')) {
  227.                 $selection[$id] = $object->getTitle();
  228.             }
  229.         }
  230.         return $selection;
  231.     }
  232.     protected function getSimilarProducts(
  233.         VirtualProduct|DataObject\AbstractObject|DataObject\Concrete|null $product,
  234.         Factory $factory
  235.     ) {
  236.         if ($product->getDecor() instanceof Decor) {
  237.             $products $factory->getIndexService()->getProductListForCurrentTenant();
  238.             $products->setVariantMode(ProductListInterface::VARIANT_MODE_HIDE);
  239.             $products->addCondition(IndexHelper::INDEX_O_CLASS_ID ' = "VirtualProduct"');
  240.             $products->addCondition('o_id != ' $product->getId() . ' AND o_id IN (SELECT src FROM ' IndexHelper::TABLE_PRODUCT_INDEX_RELATIONS ' WHERE fieldname = "decor" AND dest = "' $product->getDecor()->getId() . '" GROUP BY src)');
  241.             $products->setOrderKey('RAND()');
  242.             $products->setLimit(3);
  243.             return $products;
  244.         }
  245.         return [];
  246.     }
  247. }