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

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\System\SalesChannel\SalesChannelContext;
  15. use Symfony\Component\HttpFoundation\Session\Session;
  16. use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
  17. class FrontendSubscriber implements EventSubscriberInterface
  18. {
  19.     public $categoryRepository;
  20.     public $systemConfigService;
  21.     public $cacheInvalidator;
  22.     public $refererCategory;
  23.     public $requestStack;
  24.     public $session false;
  25.     /**
  26.      * @return array 
  27.      */
  28.     public static function getSubscribedEvents(): array
  29.     {
  30.         return [
  31.             ProductPageLoadedEvent::class => 'onProductPageLoaded',
  32.             ProductDetailRouteCacheTagsEvent::class => 'onProductDetailRouteCacheTagsEvent',
  33.             //KernelEvents::CONTROLLER => 'invalidateCache',
  34.             KernelEvents::REQUEST => 'invalidateCache'
  35.         ];
  36.     }
  37.     public function getCurrentSession()
  38.     {
  39.         if($this->session) return $this->session;
  40.         $currentRequest $this->requestStack->getCurrentRequest();
  41.         if (!$currentRequest->hasSession()) {
  42.             $currentRequest->setSession(new Session(new MockArraySessionStorage()));
  43.         }
  44.         $this->session $this->requestStack->getSession();
  45.         return $this->session;
  46.     }
  47.     /**
  48.      * 
  49.      * @param ProductDetailRouteCacheTagsEvent $event 
  50.      * @return void 
  51.      * @throws InconsistentCriteriaIdsException 
  52.      */
  53.     public function onProductDetailRouteCacheTagsEvent($event)
  54.     {
  55.         $event->addTags(['referer-category']);
  56.     }
  57.     /**
  58.      * 
  59.      * @param ProductPageLoadedEvent $event 
  60.      * @return void 
  61.      * @throws InconsistentCriteriaIdsException 
  62.      */
  63.     public function onProductPageLoaded($event)
  64.     {
  65.         $page $event->getPage();
  66.         $salesChannelContext $event->getSalesChannelContext();
  67.         $salesChannel $salesChannelContext->getSalesChannel();
  68.         // get product categories
  69.         $product $page->getProduct();
  70.         if(!$product) return;
  71.         // try to get path from referer
  72.         if($refererCategory $this->getRefererCategory($salesChannelContext$salesChannel$product$product->parentId ?? $product->id)){
  73.             $page->getHeader()->getNavigation()->setActive($refererCategory); // set active navigation item
  74.             $product->setSeoCategory($refererCategory); // sets breadcrumb
  75.             return;
  76.         }
  77.     }
  78.     private function getRefererCategory($salesChannelContext$salesChannel$product$sessionIdentificator '')
  79.     {
  80.         if(!is_null($this->refererCategory)) return $this->refererCategory;
  81.         $url $_SERVER['HTTP_REFERER'] ?? '';
  82.         foreach ($salesChannel->getDomains() as $domain) {
  83.             $url stripos($url$domain->getUrl()) === ? (str_replace($domain->getUrl(), ''$url)) : $url;
  84.         }
  85.         $url explode('?'$url2);
  86.         $url $url[0];
  87.         $url trim(strtolower($url), '/');
  88.         $this->refererCategory $this->getCategoryByUrl($url$salesChannelContext$salesChannel$product$sessionIdentificator);
  89.         $this->getCurrentSession()->set('refererCategory'$sessionIdentificator$this->refererCategory);
  90.         return  $this->refererCategory;
  91.     }
  92.     /**
  93.      * 
  94.      * @param string $url 
  95.      * @param mixed $context 
  96.      * @return CategoryEntity|false 
  97.      * @throws InconsistentCriteriaIdsException 
  98.      */
  99.     private function getCategoryByUrl($url$salesChannelContext$salesChannel$product$sessionIdentificator '')
  100.     {
  101.         $allowedBreadcrumbCategories $this->systemConfigService->get("SemesRefererBreadcrumb.config.allowedBreadcrumbCategories") ?? 'all';
  102.         $criteria = new Criteria();
  103.         $criteria->addAssociation('seoUrls');
  104.         $criteria->addFilter(new EqualsFilter('active'true));
  105.         
  106.         $categoryUrls = [];
  107.         if($allowedBreadcrumbCategories == 'onlyProductCategories'){
  108.             $categoryUrls $product->getCategoryIds();
  109.         } elseif($allowedBreadcrumbCategories == 'onlyProductCategoriesAndParents'){
  110.             $categoryUrls $product->getCategoryTree();
  111.         }
  112.         if($categoryUrls){
  113.             $criteria->addFilter(new EqualsAnyFilter('id'$categoryUrls));
  114.         }
  115.         $criteria->addFilter($this->getSalesChannelFilter($salesChannelContext));        
  116.         $categories $this->categoryRepository->search($criteria$salesChannelContext->getContext());
  117.         foreach ($categories as $category) {
  118.             /* @var $category CategoryEntity */
  119.             foreach ($category->getSeoUrls() as $seoUrl) {
  120.                 if($seoUrl->getSalesChannelId() != $salesChannel->getId()) continue;
  121.                 if(trim(strtolower($seoUrl->getSeoPathInfo()), '/') == $url){
  122.                     return $category;
  123.                 }
  124.                 if(trim(strtolower($seoUrl->getPathInfo()), '/') == $url){
  125.                     return $category;
  126.                 }
  127.             }
  128.         }
  129.         return $this->getCurrentSession()->get('refererCategory'$sessionIdentificator) ?? false;
  130.     }
  131.     private function getSalesChannelFilter(SalesChannelContext $context)
  132.     {
  133.         $ids array_filter([
  134.             $context->getSalesChannel()->getNavigationCategoryId(),
  135.             $context->getSalesChannel()->getServiceCategoryId(),
  136.             $context->getSalesChannel()->getFooterCategoryId(),
  137.         ]);
  138.         return new OrFilter(array_map(static function (string $id) {
  139.             return new ContainsFilter('path''|' $id '|');
  140.         }, $ids));
  141.     }
  142.     public function invalidateCache()
  143.     {
  144.         $this->cacheInvalidator->invalidate(['referer-category']);
  145.     }
  146. }