vendor/shopware/storefront/Framework/Seo/SeoUrlRoute/SeoUrlUpdateListener.php line 74

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Framework\Seo\SeoUrlRoute;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Content\Category\CategoryDefinition;
  5. use Shopware\Core\Content\Category\CategoryEvents;
  6. use Shopware\Core\Content\Category\Event\CategoryIndexerEvent;
  7. use Shopware\Core\Content\LandingPage\Event\LandingPageIndexerEvent;
  8. use Shopware\Core\Content\LandingPage\LandingPageEvents;
  9. use Shopware\Core\Content\Product\Events\ProductIndexerEvent;
  10. use Shopware\Core\Content\Product\ProductEvents;
  11. use Shopware\Core\Content\Seo\SeoUrlUpdater;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Indexing\EntityIndexerRegistry;
  14. use Shopware\Core\Framework\Uuid\Uuid;
  15. use Shopware\Core\System\SalesChannel\SalesChannelDefinition;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. class SeoUrlUpdateListener implements EventSubscriberInterface
  18. {
  19.     public const CATEGORY_SEO_URL_UPDATER 'category.seo-url';
  20.     public const PRODUCT_SEO_URL_UPDATER 'product.seo-url';
  21.     public const LANDING_PAGE_SEO_URL_UPDATER 'landing_page.seo-url';
  22.     /**
  23.      * @var SeoUrlUpdater
  24.      */
  25.     private $seoUrlUpdater;
  26.     /**
  27.      * @var Connection
  28.      */
  29.     private $connection;
  30.     /**
  31.      * @var EntityIndexerRegistry
  32.      */
  33.     private $indexerRegistry;
  34.     public function __construct(SeoUrlUpdater $seoUrlUpdaterConnection $connectionEntityIndexerRegistry $indexerRegistry)
  35.     {
  36.         $this->seoUrlUpdater $seoUrlUpdater;
  37.         $this->connection $connection;
  38.         $this->indexerRegistry $indexerRegistry;
  39.     }
  40.     public function detectSalesChannelEntryPoints(EntityWrittenContainerEvent $event): void
  41.     {
  42.         $properties = ['navigationCategoryId''footerCategoryId''serviceCategoryId'];
  43.         $salesChannelIds $event->getPrimaryKeysWithPropertyChange(SalesChannelDefinition::ENTITY_NAME$properties);
  44.         if (empty($salesChannelIds)) {
  45.             return;
  46.         }
  47.         $this->indexerRegistry->sendIndexingMessage(['category.indexer''product.indexer']);
  48.     }
  49.     /**
  50.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  51.      */
  52.     public static function getSubscribedEvents()
  53.     {
  54.         return [
  55.             ProductEvents::PRODUCT_INDEXER_EVENT => 'updateProductUrls',
  56.             CategoryEvents::CATEGORY_INDEXER_EVENT => 'updateCategoryUrls',
  57.             LandingPageEvents::LANDING_PAGE_INDEXER_EVENT => 'updateLandingPageUrls',
  58.             EntityWrittenContainerEvent::class => 'detectSalesChannelEntryPoints',
  59.         ];
  60.     }
  61.     public function updateCategoryUrls(CategoryIndexerEvent $event): void
  62.     {
  63.         if (\in_array(self::CATEGORY_SEO_URL_UPDATER$event->getSkip(), true)) {
  64.             return;
  65.         }
  66.         $ids array_merge($event->getIds(), $this->getCategoryChildren($event->getIds()));
  67.         $this->seoUrlUpdater->update(NavigationPageSeoUrlRoute::ROUTE_NAME$ids);
  68.     }
  69.     public function updateProductUrls(ProductIndexerEvent $event): void
  70.     {
  71.         if (\in_array(self::PRODUCT_SEO_URL_UPDATER$event->getSkip(), true)) {
  72.             return;
  73.         }
  74.         $ids array_merge($event->getIds(), $this->getProductChildren($event->getIds()));
  75.         $this->seoUrlUpdater->update(ProductPageSeoUrlRoute::ROUTE_NAME$ids);
  76.     }
  77.     public function updateLandingPageUrls(LandingPageIndexerEvent $event): void
  78.     {
  79.         if (\in_array(self::LANDING_PAGE_SEO_URL_UPDATER$event->getSkip(), true)) {
  80.             return;
  81.         }
  82.         $this->seoUrlUpdater->update(LandingPageSeoUrlRoute::ROUTE_NAME$event->getIds());
  83.     }
  84.     private function getProductChildren(array $ids): array
  85.     {
  86.         $childrenIds $this->connection->fetchAll(
  87.             'SELECT DISTINCT LOWER(HEX(id)) as id FROM product WHERE parent_id IN (:ids)',
  88.             ['ids' => Uuid::fromHexToBytesList($ids)],
  89.             ['ids' => Connection::PARAM_STR_ARRAY]
  90.         );
  91.         return array_column($childrenIds'id');
  92.     }
  93.     private function getCategoryChildren(array $ids): array
  94.     {
  95.         if (empty($ids)) {
  96.             return [];
  97.         }
  98.         $query $this->connection->createQueryBuilder();
  99.         $query->select('category.id, category.type');
  100.         $query->from('category');
  101.         foreach ($ids as $id) {
  102.             $key 'id' $id;
  103.             $query->orWhere('category.type != :type AND category.path LIKE :' $key);
  104.             $query->setParameter($key'%' $id '%');
  105.         }
  106.         $query->setParameter('type'CategoryDefinition::TYPE_LINK);
  107.         $children $query->execute()->fetchAll(\PDO::FETCH_COLUMN);
  108.         if (!$children) {
  109.             return [];
  110.         }
  111.         return Uuid::fromBytesToHexList($children);
  112.     }
  113. }