custom/plugins/NetzpBlog6/src/Subscriber/FrontendSubscriber.php line 86

  1. <?php declare(strict_types=1);
  2. namespace NetzpBlog6\Subscriber;
  3. use NetzpBlog6\Core\SearchResult;
  4. use NetzpBlog6\Helper\BlogHelper;
  5. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  9. use Shopware\Core\Framework\Struct\ArrayStruct;
  10. use Shopware\Core\Framework\Struct\StructCollection;
  11. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  12. use Shopware\Core\System\SystemConfig\SystemConfigService;
  13. use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
  14. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Component\DependencyInjection\ContainerInterface;
  17. use Symfony\Contracts\EventDispatcher\Event;
  18. class FrontendSubscriber implements EventSubscriberInterface
  19. {
  20.     final public const SEARCH_TYPE_BLOG 10;
  21.     public function __construct(private readonly ContainerInterface $container,
  22.                                 private readonly SystemConfigService $config,
  23.                                 private readonly BlogHelper $helper) {
  24.     }
  25.     public static function getSubscribedEvents(): array
  26.     {
  27.         return [
  28.             ProductPageCriteriaEvent::class    => 'onProductCriteriaLoaded',
  29.             ProductPageLoadedEvent::class      => 'loadProductPage',
  30.             'netzp.search.register'            => 'registerSearchProvider'
  31.         ];
  32.     }
  33.     public function onProductCriteriaLoaded(ProductPageCriteriaEvent $event): void
  34.     {
  35.         $this->addBlogCriteria($event->getCriteria(), $event->getSalesChannelContext()->getSalesChannelId());
  36.     }
  37.     private function addBlogCriteria(Criteria $criteriastring $salesChannelId)
  38.     {
  39.         $criteria->addAssociation('blogs');
  40.         $blogAssociation $criteria->getAssociation('blogs');
  41.         $blogAssociation->addAssociation('tags');
  42.         $blogAssociation->addAssociation('items');
  43.         $blogAssociation->addAssociation('blogmedia');
  44.         $this->helper->addBlogDateFilterAndSorting($blogAssociationtrue);
  45.         $blogAssociation->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
  46.             new EqualsFilter('category.saleschannelid'null),
  47.             new EqualsFilter('category.saleschannelid''00000000000000000000000000000000'),
  48.             new EqualsFilter('category.saleschannelid'$salesChannelId),
  49.         ]));
  50.     }
  51.     public function loadProductPage(ProductPageLoadedEvent $event): void
  52.     {
  53.         $product $event->getPage()->getProduct();
  54.         $productBlogs $product->getExtension('blogs');
  55.         $parentId $product->getParentId();
  56.         if($parentId) {
  57.             $repo $this->container->get('product.repository');
  58.             $criteria = new Criteria([$parentId]);
  59.             $this->addBlogCriteria($criteria$event->getSalesChannelContext()->getSalesChannelId());
  60.             $parentProduct $repo->search($criteria$event->getContext())->getEntities()->first();
  61.             $parentBlogs $parentProduct->getExtension('blogs');
  62.             if($parentBlogs->count() > 0) {
  63.                 $product->addExtension('blogs',
  64.                     new StructCollection(array_merge($parentBlogs->getElements(), $productBlogs->getElements()))
  65.                 );
  66.             }
  67.         }
  68.         $event->getPage()->assign([
  69.             'netzp_blogposts' => []
  70.         ]);
  71.     }
  72.     public function registerSearchProvider(Event $event)
  73.     {
  74.         $pluginConfig $this->config->get('NetzpBlog6.config');
  75.         if((bool)$pluginConfig['searchBlog'] === false) {
  76.             return;
  77.         }
  78.         $event->setData([
  79.             'key'      => 'blog',
  80.             'label'    => 'netzp.blog.searchLabel',
  81.             'function' => [$this'doSearch']
  82.         ]);
  83.     }
  84.     public function doSearch(string $querySalesChannelContext $salesChannelContextbool $isSuggest false): array
  85.     {
  86.         $results = [];
  87.         $blogEntries $this->getBlogEntries($query$salesChannelContext$isSuggest);
  88.         foreach ($blogEntries->getEntities() as $blogEntry)
  89.         {
  90.             $tmpResult = new SearchResult();
  91.             $tmpResult->setType(static::SEARCH_TYPE_BLOG);
  92.             $tmpResult->setId($blogEntry->getId());
  93.             $tmpResult->setTitle($blogEntry->getTranslated()['title'] ?? '');
  94.             $tmpResult->setDescription($blogEntry->getTranslated()['teaser'] ?? '');
  95.             if($blogEntry->getImagepreview()) {
  96.                 $tmpResult->setMedia($blogEntry->getImagepreview());
  97.             }
  98.             else if($blogEntry->getImage()) {
  99.                 $tmpResult->setMedia($blogEntry->getImage());
  100.             }
  101.             $tmpResult->setTotal($blogEntries->getTotal());
  102.             $tmpResult->addExtension('slug', new ArrayStruct(['value' => $blogEntry->getTranslated()['slug'] ?? '']));
  103.             $results[] = $tmpResult;
  104.         }
  105.         return $results;
  106.     }
  107.     private function getBlogEntries($querySalesChannelContext $salesChannelContextbool $isSuggest false)
  108.     {
  109.         $words $this->explodeSearchQuery($query);
  110.         if (count($words) > 0)
  111.         {
  112.             $repo $this->container->get('s_plugin_netzp_blog.repository');
  113.             $criteria = new Criteria();
  114.             $criteria->addAssociation('category');
  115.             $criteria->addAssociation('image');
  116.             $criteria->addAssociation('imagepreview');
  117.             $this->helper->addBlogDateFilterAndSorting($criteriatrue);
  118.             $this->helper->addRestrictionsFilter($criteria$salesChannelContext);
  119.             if($isSuggest) {
  120.                 $criteria->setLimit(10);
  121.                 $criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
  122.             }
  123.             $filter = [];
  124.             foreach ($words as $word) {
  125.                 $filter[] = new ContainsFilter('title'$word);
  126.                 $filter[] = new ContainsFilter('teaser'$word);
  127.                 $filter[] = new ContainsFilter('contents'$word);
  128.             }
  129.             $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR$filter));
  130.             return $repo->search($criteria$salesChannelContext->getContext());
  131.         }
  132.         return null;
  133.     }
  134.     private function explodeSearchQuery(string $query): array
  135.     {
  136.         $query trim((string)$query);
  137.         if(str_starts_with($query'"') && str_ends_with($query'"'))
  138.         {
  139.             return [ trim($query'"') ];
  140.         }
  141.         return explode(' '$query);
  142.     }
  143. }