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

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