platform/src/Storefront/Framework/Seo/SeoUrlRoute/SeoUrlUpdateListener.php line 71

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.     public static function getSubscribedEvents()
  50.     {
  51.         return [
  52.             ProductEvents::PRODUCT_INDEXER_EVENT => 'updateProductUrls',
  53.             CategoryEvents::CATEGORY_INDEXER_EVENT => 'updateCategoryUrls',
  54.             LandingPageEvents::LANDING_PAGE_INDEXER_EVENT => 'updateLandingPageUrls',
  55.             EntityWrittenContainerEvent::class => 'detectSalesChannelEntryPoints',
  56.         ];
  57.     }
  58.     public function updateCategoryUrls(CategoryIndexerEvent $event): void
  59.     {
  60.         if (\in_array(self::CATEGORY_SEO_URL_UPDATER$event->getSkip(), true)) {
  61.             return;
  62.         }
  63.         $ids array_merge($event->getIds(), $this->getCategoryChildren($event->getIds()));
  64.         $this->seoUrlUpdater->update(NavigationPageSeoUrlRoute::ROUTE_NAME$ids);
  65.     }
  66.     public function updateProductUrls(ProductIndexerEvent $event): void
  67.     {
  68.         if (\in_array(self::PRODUCT_SEO_URL_UPDATER$event->getSkip(), true)) {
  69.             return;
  70.         }
  71.         $ids array_merge($event->getIds(), $this->getProductChildren($event->getIds()));
  72.         $this->seoUrlUpdater->update(ProductPageSeoUrlRoute::ROUTE_NAME$ids);
  73.     }
  74.     public function updateLandingPageUrls(LandingPageIndexerEvent $event): void
  75.     {
  76.         if (\in_array(self::LANDING_PAGE_SEO_URL_UPDATER$event->getSkip(), true)) {
  77.             return;
  78.         }
  79.         $this->seoUrlUpdater->update(LandingPageSeoUrlRoute::ROUTE_NAME$event->getIds());
  80.     }
  81.     private function getProductChildren(array $ids): array
  82.     {
  83.         $childrenIds $this->connection->fetchAll(
  84.             'SELECT DISTINCT LOWER(HEX(id)) as id FROM product WHERE parent_id IN (:ids)',
  85.             ['ids' => Uuid::fromHexToBytesList($ids)],
  86.             ['ids' => Connection::PARAM_STR_ARRAY]
  87.         );
  88.         return array_column($childrenIds'id');
  89.     }
  90.     private function getCategoryChildren(array $ids): array
  91.     {
  92.         if (empty($ids)) {
  93.             return [];
  94.         }
  95.         $query $this->connection->createQueryBuilder();
  96.         $query->select('category.id, category.type');
  97.         $query->from('category');
  98.         foreach ($ids as $id) {
  99.             $key 'id' $id;
  100.             $query->orWhere('category.type != :type AND category.path LIKE :' $key);
  101.             $query->setParameter($key'%' $id '%');
  102.         }
  103.         $query->setParameter('type'CategoryDefinition::TYPE_LINK);
  104.         $children $query->execute()->fetchAll(\PDO::FETCH_COLUMN);
  105.         if (!$children) {
  106.             return [];
  107.         }
  108.         return Uuid::fromBytesToHexList($children);
  109.     }
  110. }