custom/plugins/SemesRefererBreadcrumb/src/Subscriber/FrontendSubscriber.php line 156

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Semes\RefererBreadcrumb\Subscriber;
  3. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  4. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  6. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\OrFilter;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  11. use Shopware\Core\Content\Category\CategoryEntity;
  12. use Shopware\Core\Content\Product\Events\ProductDetailRouteCacheTagsEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. use Shopware\Core\Framework\Adapter\Cache\CacheInvalidator;
  15. use Shopware\Core\System\SystemConfig\SystemConfigService;
  16. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  17. class FrontendSubscriber implements EventSubscriberInterface
  18. {
  19.     public $categoryRepository;
  20.     public $systemConfigService;
  21.     public $cacheInvalidator;
  22.     public $refererCategory;
  23.     /**
  24.      * @return array 
  25.      */
  26.     public static function getSubscribedEvents(): array
  27.     {
  28.         return [
  29.             ProductPageLoadedEvent::class => 'onProductPageLoaded',
  30.             ProductDetailRouteCacheTagsEvent::class => 'onProductDetailRouteCacheTagsEvent',
  31.             //KernelEvents::CONTROLLER => 'invalidateCache',
  32.             KernelEvents::REQUEST => 'invalidateCache'
  33.         ];
  34.     }
  35.     /**
  36.      * 
  37.      * @param ProductDetailRouteCacheTagsEvent $event 
  38.      * @return void 
  39.      * @throws InconsistentCriteriaIdsException 
  40.      */
  41.     public function onProductDetailRouteCacheTagsEvent($event)
  42.     {
  43.         $event->addTags(['referer-category']);
  44.     }
  45.     /**
  46.      * 
  47.      * @param ProductPageLoadedEvent $event 
  48.      * @return void 
  49.      * @throws InconsistentCriteriaIdsException 
  50.      */
  51.     public function onProductPageLoaded($event)
  52.     {
  53.         $page $event->getPage();
  54.         $salesChannelContext $event->getSalesChannelContext();
  55.         $salesChannel $salesChannelContext->getSalesChannel();
  56.         // get product categories
  57.         $product $page->getProduct();
  58.         if(!$product) return;
  59.         // try to get path from referer
  60.         if($refererCategory $this->getRefererCategory($salesChannelContext$salesChannel$product)){
  61.             $page->getHeader()->getNavigation()->setActive($refererCategory); // set active navigation item
  62.             $product->setSeoCategory($refererCategory); // sets breadcrumb
  63.             return;
  64.         }
  65.     }
  66.     private function getRefererCategory($salesChannelContext$salesChannel$product)
  67.     {
  68.         if(!is_null($this->refererCategory)) return $this->refererCategory;
  69.         $url $_SERVER['HTTP_REFERER'] ?? '';
  70.         foreach ($salesChannel->getDomains() as $domain) {
  71.             $url stripos($url$domain->getUrl()) === ? (str_replace($domain->getUrl(), ''$url)) : $url;
  72.         }
  73.         $url explode('?'$url2);
  74.         $url $url[0];
  75.         $url trim(strtolower($url), '/');
  76.         $this->refererCategory $this->getCategoryByUrl($url$salesChannelContext$salesChannel$product);
  77.         return  $this->refererCategory;
  78.     }
  79.     /**
  80.      * 
  81.      * @param string $url 
  82.      * @param mixed $context 
  83.      * @return CategoryEntity|false 
  84.      * @throws InconsistentCriteriaIdsException 
  85.      */
  86.     private function getCategoryByUrl($url$salesChannelContext$salesChannel$product)
  87.     {
  88.         $allowedBreadcrumbCategories $this->systemConfigService->get("SemesRefererBreadcrumb.config.allowedBreadcrumbCategories") ?? 'all';
  89.         $criteria = new Criteria();
  90.         $criteria->addAssociation('seoUrls');
  91.         $criteria->addFilter(new EqualsFilter('active'true));
  92.         
  93.         $categoryUrls = [];
  94.         if($allowedBreadcrumbCategories == 'onlyProductCategories'){
  95.             $categoryUrls $product->getCategoryIds();
  96.         } elseif($allowedBreadcrumbCategories == 'onlyProductCategoriesAndParents'){
  97.             $categoryUrls $product->getCategoryTree();
  98.         }
  99.         if($categoryUrls){
  100.             $criteria->addFilter(new EqualsAnyFilter('id'$categoryUrls));
  101.         }
  102.         $criteria->addFilter($this->getSalesChannelFilter($salesChannelContext));        
  103.         $categories $this->categoryRepository->search($criteria$salesChannelContext->getContext());
  104.         foreach ($categories as $category) {
  105.             /* @var $category CategoryEntity */
  106.             foreach ($category->getSeoUrls() as $seoUrl) {
  107.                 if($seoUrl->getSalesChannelId() != $salesChannel->getId()) continue;
  108.                 if(trim(strtolower($seoUrl->getSeoPathInfo()), '/') == $url){
  109.                     return $category;
  110.                 }
  111.                 if(trim(strtolower($seoUrl->getPathInfo()), '/') == $url){
  112.                     return $category;
  113.                 }
  114.             }
  115.         }
  116.         return false;
  117.     }
  118.     private function getSalesChannelFilter(SalesChannelContext $context)
  119.     {
  120.         $ids array_filter([
  121.             $context->getSalesChannel()->getNavigationCategoryId(),
  122.             $context->getSalesChannel()->getServiceCategoryId(),
  123.             $context->getSalesChannel()->getFooterCategoryId(),
  124.         ]);
  125.         return new OrFilter(array_map(static function (string $id) {
  126.             return new ContainsFilter('path''|' $id '|');
  127.         }, $ids));
  128.     }
  129.     public function invalidateCache()
  130.     {
  131.         $this->cacheInvalidator->invalidate(['referer-category']);
  132.     }
  133. }