custom/plugins/CogiGlossary/src/Subscriber/StorefrontSubscriber.php line 81

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace CogiGlossary\Subscriber;
  3. use Composer\IO\NullIO;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\FetchMode;
  6. use Doctrine\DBAL\ParameterType;
  7. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  8. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  11. use Shopware\Core\Framework\Struct\ArrayEntity;
  12. use Shopware\Core\System\SystemConfig\SystemConfigService;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\Filter;
  17. use Shopware\Core\Content\Cms\CmsPageEvents;
  18. use Shopware\Core\Framework\Struct\Struct;
  19. use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
  20. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  21. use Shopware\Core\Content\Cms\Events\CmsPageLoadedEvent;
  22. use Shopware\Core\Framework\Api\Context\SalesChannelApiSource;
  23. use Shopware\Core\Framework\DataAbstractionLayer\Search\Grouping\FieldGrouping;
  24. class StorefrontSubscriber implements EventSubscriberInterface
  25. {
  26.     private $systemConfigService;
  27.     private $mediaRepository;
  28.     private $connection;
  29.     /**
  30.      * @var SeoUrlPlaceholderHandlerInterface
  31.      */
  32.     private $seoUrlReplacer;
  33.     /**
  34.      * @var EntityRepositoryInterface
  35.      */
  36.     private $repository;
  37.     public function __construct(
  38.         SystemConfigService $systemConfigService,
  39.         SeoUrlPlaceholderHandlerInterface $seoUrlReplacer,
  40.         EntityRepositoryInterface $repository,
  41.         Connection $connection
  42.     )
  43.     {
  44.         $this->systemConfigService $systemConfigService;
  45.         $this->seoUrlReplacer $seoUrlReplacer;
  46.         $this->repository $repository;
  47.         $this->connection $connection;
  48.     }
  49.     public static function getSubscribedEvents(): array
  50.     {
  51.         return [
  52.             CmsPageEvents::SLOT_LOADED_EVENT => 'onEntityLoadedEvent',
  53.             ProductPageLoadedEvent::class => 'onProductPageLoadedEvent'
  54.         ];
  55.     }
  56.     public function onProductPageLoadedEvent(ProductPageLoadedEvent $event): void
  57.     {
  58.         if (!$this->systemConfigService->get('CogiGlossary.config.highlight')) {
  59.             return;
  60.         }
  61.         $replace $this->prepareGlossary($event);
  62.         $product $event->getPage()->getProduct()->getTranslated();
  63.         $product['description'] = str_replace($replace['from'], $replace['to'], $product['description']);
  64.         $event->getPage()->getProduct()->setTranslated($product);
  65.     }
  66.     public function onEntityLoadedEvent(EntityLoadedEvent $event): void
  67.     {
  68.         if (!$this->systemConfigService->get('CogiGlossary.config.highlight')) {
  69.             return;
  70.         }
  71.         $source $event->getContext()->getSource();
  72.         if (!$source instanceof SalesChannelApiSource) {
  73.             return;
  74.         }
  75.         $replace $this->prepareGlossary($event);
  76.         $entities $event->getEntities();
  77.         foreach ($entities as $entity) {
  78.             if ($entity->getType() == 'text') {
  79.                 $config $entity->getTranslated();
  80.                 foreach ($config['config'] as &$item) {
  81.                     if ($item['value'] && $this->isHTML($item['value'])) {
  82.                         $dom = new \DOMDocument();
  83.                         @$dom->loadHTML(mb_convert_encoding($item['value'], 'HTML-ENTITIES''UTF-8'));
  84.                         $preparedHTML $dom->saveHTML($this->nodeReplace($replace['from'], $replace['node'], $dom));
  85.                         $item['value'] = str_replace($replace['node'], $replace['to'], $preparedHTML);
  86.                     }
  87.                 }
  88.                 $entity->setTranslated($config);
  89.             }
  90.         }
  91.     }
  92.     private function prepareGlossary($event)
  93.     {
  94.         $criteria = new Criteria();
  95.         $criteria->addFilter(new EqualsFilter('active'1));
  96.         $criteria->addAssociation('media');
  97.         $replaceFrom = [];
  98.         $replaceNode = [];
  99.         $replaceTo = [];
  100.         $cogiGlossary $this->repository->search($criteria$event->getContext())->getEntities();
  101.         foreach ($cogiGlossary as $item) {
  102.             $replaceFrom[] = $item->getName();
  103.             $replaceNode[] = '###' $item->getName() . '###';
  104.             if ($this->systemConfigService->get('CogiGlossary.config.directUrl')) {
  105.                 $url $this->seoUrlReplacer->generate('cogi-glossary.article', ['firstChar' => $item->getFirstChar(), 'glossaryId' => $item->getId()]);
  106.             } else {
  107.                 $url $this->seoUrlReplacer->generate('cogi-glossary.index', ['firstChar' => $item->getFirstChar()]) . '#' $item->getName();
  108.             }
  109.             if ($this->systemConfigService->get('CogiGlossary.config.hovercard')) {
  110.                 $replaceTo[] = '<a class="glossary-link" title="' $item->getName() . '" data-cogi-glossary-hover="' $this->seoUrlReplacer->generate('cogi-glossary.hover', ['glossaryId' => $item->getId()]) . '" href="' .$url.'">' $item->getName() . '</a>';
  111.             } else {
  112.                 $replaceTo[] = '<a class="glossary-link" title="' $item->getName() . '" href="' .$url.'">' $item->getName() . '</a>';
  113.             }
  114.         }
  115.         return [
  116.             'from' => $replaceFrom,
  117.             'node' => $replaceNode,
  118.             'to' => $replaceTo
  119.         ];
  120.     }
  121.     private function nodeReplace($replaceFrom$replaceTo$node)
  122.     {
  123.         if ($node instanceof \DOMElement) {
  124.             if (in_array($node->nodeName, ['a''button''h1''h2''h3''h4''h5'])) {
  125.                 return $node;
  126.             }
  127.         }
  128.         if ($node instanceof \DOMText) {
  129.             $node->data str_replace($replaceFrom$replaceTo$node->data);
  130.         }
  131.         if ($node->childNodes) {
  132.             foreach ($node->childNodes AS $child) {
  133.                 $this->nodeReplace($replaceFrom$replaceTo$child);
  134.             }
  135.         }
  136.         return $node;
  137.     }
  138.     private function isHTML($string)
  139.     {
  140.         if(!is_string($string)){
  141.             return false;
  142.         }
  143.         return $string != strip_tags($string) ? true false;
  144.     }
  145. }