custom/plugins/LoyxxRichBreadcrumb/src/Subscriber/ProductPageLoadedEvent.php line 240

Open in your IDE?
  1. <?php
  2. namespace LoyxxRichBreadcrumb\Subscriber;
  3. use Doctrine\DBAL\Connection;
  4. use LoyxxRichBreadcrumb\Struct\Breadcrumb;
  5. use LoyxxRichBreadcrumb\Struct\Data;
  6. use LoyxxRichBreadcrumb\Traits\Microdata;
  7. use Shopware\Core\Content\Seo\SeoUrl\SeoUrlEntity;
  8. use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
  9. use Shopware\Core\Framework\Adapter\Cache\CacheClearer;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  15. use Shopware\Core\Framework\Struct\ArrayStruct;
  16. use Shopware\Core\System\SystemConfig\SystemConfigService;
  17. use Shopware\Storefront\Controller\NavigationController;
  18. use Shopware\Storefront\Controller\ProductController;
  19. use Shopware\Storefront\Framework\Routing\RequestTransformer;
  20. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  21. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  22. use Symfony\Component\HttpKernel\KernelEvents;
  23. /**
  24.  * Class ProductPageLoadedEvent
  25.  * @package LoyxxRichBreadcrumb\Subscriber
  26.  */
  27. class ProductPageLoadedEvent implements EventSubscriberInterface
  28. {
  29.     use Microdata;
  30.     public const SESSION_SEO_CATEGORY 'seoCategory';
  31.     public const SESSION_SEO_CATEGORY_ID 'seoCategoryId';
  32.     /**
  33.      * @var SeoUrlPlaceholderHandlerInterface
  34.      */
  35.     private $seoUrlPlaceholderHandler;
  36.     /**
  37.      * @var SystemConfigService
  38.      */
  39.     private $systemConfigService;
  40.     /**
  41.      * @var EntityRepositoryInterface
  42.      */
  43.     private $seoUrlRepository;
  44.     /**
  45.      * @var Connection
  46.      */
  47.     private $connection;
  48.     /**
  49.      * @var EntityRepositoryInterface
  50.      */
  51.     private  $categoryRepository;
  52.     /**
  53.      * @var CacheClearer
  54.      */
  55.     private  $cacheClearer;
  56.     /**
  57.      * ProductPageLoadedEvent constructor.
  58.      * @param SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler
  59.      * @param SystemConfigService $systemConfigService
  60.      * @param EntityRepositoryInterface $seoUrlRepository
  61.      * @param Connection $connection
  62.      */
  63.     public function __construct(
  64.         SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
  65.         SystemConfigService $systemConfigService,
  66.         EntityRepositoryInterface $seoUrlRepository,
  67.         EntityRepositoryInterface $categoryRepository,
  68.         Connection $connection,
  69.         CacheClearer $cacheClearer
  70.     )
  71.     {
  72.         $this->seoUrlPlaceholderHandler $seoUrlPlaceholderHandler;
  73.         $this->systemConfigService $systemConfigService;
  74.         $this->seoUrlRepository $seoUrlRepository;
  75.         $this->connection $connection;
  76.         $this->categoryRepository $categoryRepository;
  77.         $this->cacheClearer $cacheClearer;
  78.     }
  79.     /**
  80.      * @return array|string[]
  81.      */
  82.     public static function getSubscribedEvents(): array
  83.     {
  84.         return [
  85.             \Shopware\Storefront\Page\Product\ProductPageLoadedEvent::class => 'onProductPageLoadedEvent',
  86.             KernelEvents::CONTROLLER => 'onControllerEvent'
  87.         ];
  88.     }
  89.     /**
  90.      * @param \Shopware\Storefront\Page\Product\ProductPageLoadedEvent $event
  91.      */
  92.     public function onProductPageLoadedEvent(\Shopware\Storefront\Page\Product\ProductPageLoadedEvent $event)
  93.     {
  94.         // create microdata for breadcrumb
  95.         $host $event->getRequest()->attributes->get(RequestTransformer::SALES_CHANNEL_ABSOLUTE_BASE_URL) .
  96.             $event->getRequest()->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);
  97.         $uri $event->getRequest()->getRequestUri();
  98.         if ( $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.modifyProductDetailBreadcrumb')){
  99.             $this->checkAndUpdateSeoBreadcrumbNavigation($event$host);
  100.         }
  101.         $navigationTree $event->getPage()->getHeader()->getNavigation()->getTree();
  102.         $product $event->getPage()->getProduct();
  103.         $productBreadcrumb = [];
  104.         $this->createBreadcrumbTree($navigationTree$product$productBreadcrumb);
  105.         /**
  106.          * Hide breadcrumb on home page
  107.          *
  108.          * $breadcrumbIsVisible = $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME.'.config.isInvisible');
  109.          * if ($this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.isHiddenOnHomePage') && $event->getRequest()->attributes->get('_route') === 'frontend.home.page'){
  110.          * $breadcrumbIsVisible = false;
  111.          * }
  112.          *  */
  113.         $breadcrumbStruct = new Breadcrumb(
  114.             $this->createMicrodata(
  115.                 $event,
  116.                 $productBreadcrumb,
  117.                 $host,
  118.                 $event->getSalesChannelContext(),
  119.                 $uri
  120.             ),
  121.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.isInvisible'),
  122.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.showProductTitle'),
  123.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.separator'),
  124.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.isVisibleHomeLink'),
  125.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.isHiddenOnHomePage'),
  126.             $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.homeLabel'),
  127.             $host,
  128.             $uri
  129.         );
  130.         $event->getPage()->addExtension('breadcrumb'$breadcrumbStruct);
  131.         $event->getPage()->getProduct()->addExtension('breadcrumb'$breadcrumbStruct);
  132.         $event->getSalesChannelContext()->addExtensions([
  133.             'breadcrumb' => $breadcrumbStruct,
  134.             'breadcrumbProduct' => new ArrayStruct(['product' => $event->getPage()->getProduct()])
  135.         ]);
  136.     }
  137.     public function checkAndUpdateSeoBreadcrumbNavigation(\Shopware\Storefront\Page\Product\ProductPageLoadedEvent $eventstring $host)
  138.     {
  139.         $referer $event->getRequest()->server->get('HTTP_REFERER');
  140.         $session $event->getRequest()->getSession();
  141.         $sessionCategoryId $session->get(self::SESSION_SEO_CATEGORY_ID);
  142.         $categoryTree $event->getPage()->getProduct()->getCategoryTree();
  143.         if ($categoryTree && $sessionCategoryId && in_array($sessionCategoryId$categoryTree)){
  144.             $category $this->categoryRepository->search(new Criteria([$sessionCategoryId]), $event->getContext())->first();
  145.             if ($category){
  146.                 $event->getRequest()->getSession()->set(static::SESSION_SEO_CATEGORY$category);
  147.             }
  148.         }else{
  149.             $session->remove(self::SESSION_SEO_CATEGORY_ID);
  150.             $session->remove(self::SESSION_SEO_CATEGORY);
  151.         }
  152.         if (($referer && $referer !== $host) && is_null($sessionCategoryId)) {
  153.             $referer str_replace($host""$referer);
  154.             // remove ? and # from fragment from the URI
  155.             $referer ltrim(substr(substr($referer0strrpos($referer'?') ?: strlen($referer)), 0strrpos($referer'#') ?: strlen($referer)), "/");
  156.             if ($referer){
  157.                 // get the navigation id if it present in the seoUrl page
  158.                 $criteria = new Criteria();
  159.                 $criteria->setLimit(1);
  160.                 $criteria->setTotalCountMode(1);
  161.                 $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
  162.                     new EqualsFilter('seoPathInfo'"$referer"),
  163.                     new EqualsFilter('seoPathInfo'"{$referer}/")
  164.                 ]));
  165.                 /** @var SeoUrlEntity $seoUrl */
  166.                 $seoUrl $this->seoUrlRepository->search($criteria$event->getContext())->first();
  167.                 if(is_null($seoUrl)){
  168.                     // the received $lastPart was a uuid
  169.                     $criteria = new Criteria();
  170.                     $criteria->setLimit(1);
  171.                     $criteria->setTotalCountMode(1);
  172.                     $criteria->addFilter(new ContainsFilter('pathInfo'$referer));
  173.                     $seoUrl $this->seoUrlRepository->search($criteria$event->getContext())->first();
  174.                 }
  175.                 if ($seoUrl){
  176.                     $categoryId $seoUrl->getForeignKey();
  177.                     // check existence of the category
  178.                     $rows $this->connection->executeQuery("SELECT count(id) as row_count FROM category WHERE hex(id) = ?", [$categoryId]);
  179.                     $row $rows->fetch(\PDO::FETCH_ASSOC);
  180.                     if (isset($row['row_count']) && $row['row_count']){
  181.                         $category $this->categoryRepository->search(new Criteria([$categoryId]), $event->getContext())->first();
  182.                         if ($category){
  183.                             $event->getRequest()->getSession()->set(static::SESSION_SEO_CATEGORY$category);
  184.                         }
  185.                     }
  186.                 }
  187.             }
  188.         }
  189.     }
  190.     /**
  191.      * @param array $navigationTree
  192.      * @param \Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity $product
  193.      * @param $productBreadcrumb
  194.      */
  195.     private function createBreadcrumbTree(array $navigationTree\Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity $product, &$productBreadcrumb)
  196.     {
  197.         if ($navigationTree) {
  198.             $productCategoryTree $product->getCategoryTree();
  199.             if ($productCategoryTree){
  200.                 $lastProductCategoryTree end($productCategoryTree);
  201.                 foreach ($navigationTree as $item) {
  202.                     if ($item->getCategory()->getId() == $lastProductCategoryTree) {
  203.                         $breadcrumb $item->getCategory()->getPlainBreadcrumb($item->getCategory()->getId());
  204.                         $breadcrumb array_slice($breadcrumb1);
  205.                         if ($breadcrumb) {
  206.                             foreach ($breadcrumb as $key => $value) {
  207.                                 $productBreadcrumb[$key] = $value;
  208.                             }
  209.                         }
  210.                     } else if ($item->getChildren()) {
  211.                         $this->createBreadcrumbTree($item->getChildren(), $product$productBreadcrumb);
  212.                     }
  213.                 }
  214.             }
  215.         }
  216.     }
  217.     public function onControllerEvent(ControllerEvent $event): void {
  218.         if ( $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME '.config.modifyProductDetailBreadcrumb')){
  219.             $controller $event->getController();
  220.             $clearCache is_array($controller) && count($controller) === && $controller[0] instanceof NavigationController && $controller[1] === 'index';
  221.             if($clearCache){ // clear cache only for the navigation and product detail page
  222.                 $this->cacheClearer->clear();
  223.             }
  224.         }
  225.     }
  226. }