vendor/shopware/platform/src/Core/Framework/Adapter/Cache/CacheInvalidationSubscriber.php line 165

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Adapter\Cache;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Checkout\Cart\CachedRuleLoader;
  5. use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroup\CustomerGroupDefinition;
  6. use Shopware\Core\Checkout\Payment\PaymentMethodDefinition;
  7. use Shopware\Core\Checkout\Payment\SalesChannel\CachedPaymentMethodRoute;
  8. use Shopware\Core\Checkout\Shipping\SalesChannel\CachedShippingMethodRoute;
  9. use Shopware\Core\Checkout\Shipping\ShippingMethodDefinition;
  10. use Shopware\Core\Content\Category\CategoryDefinition;
  11. use Shopware\Core\Content\Category\Event\CategoryIndexerEvent;
  12. use Shopware\Core\Content\Category\SalesChannel\CachedCategoryRoute;
  13. use Shopware\Core\Content\Category\SalesChannel\CachedNavigationRoute;
  14. use Shopware\Core\Content\Cms\CmsPageDefinition;
  15. use Shopware\Core\Content\LandingPage\Event\LandingPageIndexerEvent;
  16. use Shopware\Core\Content\LandingPage\SalesChannel\CachedLandingPageRoute;
  17. use Shopware\Core\Content\Product\Aggregate\ProductCategory\ProductCategoryDefinition;
  18. use Shopware\Core\Content\Product\Aggregate\ProductCrossSelling\ProductCrossSellingDefinition;
  19. use Shopware\Core\Content\Product\Aggregate\ProductManufacturer\ProductManufacturerDefinition;
  20. use Shopware\Core\Content\Product\Events\ProductChangedEventInterface;
  21. use Shopware\Core\Content\Product\Events\ProductIndexerEvent;
  22. use Shopware\Core\Content\Product\Events\ProductNoLongerAvailableEvent;
  23. use Shopware\Core\Content\Product\ProductDefinition;
  24. use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CachedProductCrossSellingRoute;
  25. use Shopware\Core\Content\Product\SalesChannel\Detail\CachedProductDetailRoute;
  26. use Shopware\Core\Content\Product\SalesChannel\Listing\CachedProductListingRoute;
  27. use Shopware\Core\Content\Product\SalesChannel\Review\CachedProductReviewRoute;
  28. use Shopware\Core\Content\ProductStream\ProductStreamDefinition;
  29. use Shopware\Core\Content\Property\PropertyGroupDefinition;
  30. use Shopware\Core\Content\Rule\Event\RuleIndexerEvent;
  31. use Shopware\Core\Content\Seo\CachedSeoResolver;
  32. use Shopware\Core\Content\Seo\Event\SeoUrlUpdateEvent;
  33. use Shopware\Core\Content\Sitemap\Event\SitemapGeneratedEvent;
  34. use Shopware\Core\Content\Sitemap\SalesChannel\CachedSitemapRoute;
  35. use Shopware\Core\Defaults;
  36. use Shopware\Core\Framework\Adapter\Translation\Translator;
  37. use Shopware\Core\Framework\DataAbstractionLayer\Cache\EntityCacheKeyGenerator;
  38. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
  39. use Shopware\Core\Framework\Plugin\Event\PluginPostActivateEvent;
  40. use Shopware\Core\Framework\Plugin\Event\PluginPostDeactivateEvent;
  41. use Shopware\Core\Framework\Plugin\Event\PluginPostInstallEvent;
  42. use Shopware\Core\Framework\Plugin\Event\PluginPostUninstallEvent;
  43. use Shopware\Core\Framework\Plugin\Event\PluginPostUpdateEvent;
  44. use Shopware\Core\Framework\Uuid\Uuid;
  45. use Shopware\Core\System\Country\CountryDefinition;
  46. use Shopware\Core\System\Country\SalesChannel\CachedCountryRoute;
  47. use Shopware\Core\System\Currency\CurrencyDefinition;
  48. use Shopware\Core\System\Currency\SalesChannel\CachedCurrencyRoute;
  49. use Shopware\Core\System\Language\LanguageDefinition;
  50. use Shopware\Core\System\Language\SalesChannel\CachedLanguageRoute;
  51. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelCountry\SalesChannelCountryDefinition;
  52. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelCurrency\SalesChannelCurrencyDefinition;
  53. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelLanguage\SalesChannelLanguageDefinition;
  54. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelPaymentMethod\SalesChannelPaymentMethodDefinition;
  55. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelShippingMethod\SalesChannelShippingMethodDefinition;
  56. use Shopware\Core\System\SalesChannel\Context\CachedSalesChannelContextFactory;
  57. use Shopware\Core\System\SalesChannel\SalesChannelDefinition;
  58. use Shopware\Core\System\Salutation\SalesChannel\CachedSalutationRoute;
  59. use Shopware\Core\System\Salutation\SalutationDefinition;
  60. use Shopware\Core\System\Snippet\SnippetDefinition;
  61. use Shopware\Core\System\SystemConfig\CachedSystemConfigLoader;
  62. use Shopware\Core\System\SystemConfig\Event\SystemConfigChangedEvent;
  63. use Shopware\Core\System\SystemConfig\SystemConfigService;
  64. use Shopware\Core\System\Tax\TaxDefinition;
  65. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  66. /**
  67.  * @internal - The functions inside this class are no public-api and can be changed without previous deprecation
  68.  */
  69. class CacheInvalidationSubscriber implements EventSubscriberInterface
  70. {
  71.     private Connection $connection;
  72.     private CacheInvalidator $logger;
  73.     public function __construct(
  74.         CacheInvalidator $logger,
  75.         Connection $connection
  76.     ) {
  77.         $this->logger $logger;
  78.         $this->connection $connection;
  79.     }
  80.     public static function getSubscribedEvents()
  81.     {
  82.         return [
  83.             CategoryIndexerEvent::class => [
  84.                 ['invalidateCategoryRouteByCategoryIds'2000],
  85.                 ['invalidateListingRouteByCategoryIds'2001],
  86.             ],
  87.             LandingPageIndexerEvent::class => [
  88.                 ['invalidateIndexedLandingPages'2000],
  89.             ],
  90.             ProductIndexerEvent::class => [
  91.                 ['invalidateSearch'2000],
  92.                 ['invalidateListings'2001],
  93.                 ['invalidateProductIds'2002],
  94.                 ['invalidateDetailRoute'2004],
  95.                 ['invalidateStreamsAfterIndexing'2005],
  96.                 ['invalidateReviewRoute'2006],
  97.             ],
  98.             ProductNoLongerAvailableEvent::class => [
  99.                 ['invalidateSearch'2000],
  100.                 ['invalidateListings'2001],
  101.                 ['invalidateProductIds'2002],
  102.                 ['invalidateDetailRoute'2004],
  103.                 ['invalidateStreamsAfterIndexing'2005],
  104.                 ['invalidateReviewRoute'2006],
  105.             ],
  106.             EntityWrittenContainerEvent::class => [
  107.                 ['invalidateCmsPageIds'2001],
  108.                 ['invalidateCurrencyRoute'2002],
  109.                 ['invalidateLanguageRoute'2003],
  110.                 ['invalidateNavigationRoute'2004],
  111.                 ['invalidatePaymentMethodRoute'2005],
  112.                 ['invalidateProductAssignment'2006],
  113.                 ['invalidateManufacturerFilters'2007],
  114.                 ['invalidatePropertyFilters'2008],
  115.                 ['invalidateCrossSellingRoute'2009],
  116.                 ['invalidateContext'2010],
  117.                 ['invalidateShippingMethodRoute'2011],
  118.                 ['invalidateSnippets'2012],
  119.                 ['invalidateStreamsBeforeIndexing'2013],
  120.                 ['invalidateStreamIds'2014],
  121.                 ['invalidateCountryRoute'2015],
  122.                 ['invalidateSalutationRoute'2016],
  123.             ],
  124.             SeoUrlUpdateEvent::class => [
  125.                 ['invalidateSeoUrls'2000],
  126.             ],
  127.             RuleIndexerEvent::class => [
  128.                 ['invalidateRules'2000],
  129.             ],
  130.             PluginPostInstallEvent::class => [
  131.                 ['invalidateRules'2000],
  132.                 ['invalidateConfig'2001],
  133.             ],
  134.             PluginPostActivateEvent::class => [
  135.                 ['invalidateRules'2000],
  136.                 ['invalidateConfig'2001],
  137.             ],
  138.             PluginPostUpdateEvent::class => [
  139.                 ['invalidateRules'2000],
  140.                 ['invalidateConfig'2001],
  141.             ],
  142.             PluginPostDeactivateEvent::class => [
  143.                 ['invalidateRules'2000],
  144.                 ['invalidateConfig'2001],
  145.             ],
  146.             PluginPostUninstallEvent::class => [
  147.                 ['invalidateRules'2000],
  148.                 ['invalidateConfig'2001],
  149.             ],
  150.             SystemConfigChangedEvent::class => [
  151.                 ['invalidateConfigKey'2000],
  152.             ],
  153.             SitemapGeneratedEvent::class => [
  154.                 ['invalidateSitemap'2000],
  155.             ],
  156.         ];
  157.     }
  158.     public function invalidateSitemap(SitemapGeneratedEvent $event): void
  159.     {
  160.         $this->logger->invalidate([
  161.             CachedSitemapRoute::buildName($event->getSalesChannelContext()->getSalesChannelId()),
  162.         ]);
  163.     }
  164.     public function invalidateConfig(): void
  165.     {
  166.         // invalidates the complete cached config
  167.         $this->logger->invalidate([
  168.             CachedSystemConfigLoader::CACHE_TAG,
  169.         ]);
  170.     }
  171.     public function invalidateConfigKey(SystemConfigChangedEvent $event): void
  172.     {
  173.         // invalidates the complete cached config and routes which access a specific key
  174.         $this->logger->invalidate([
  175.             SystemConfigService::buildName($event->getKey()),
  176.             CachedSystemConfigLoader::CACHE_TAG,
  177.         ]);
  178.     }
  179.     public function invalidateSnippets(EntityWrittenContainerEvent $event): void
  180.     {
  181.         // invalidates all http cache items where the snippets used
  182.         $snippets $event->getEventByEntityName(SnippetDefinition::ENTITY_NAME);
  183.         if (!$snippets) {
  184.             return;
  185.         }
  186.         $tags = [];
  187.         foreach ($snippets->getPayloads() as $payload) {
  188.             if (isset($payload['translationKey'])) {
  189.                 $tags[] = Translator::buildName($payload['translationKey']);
  190.             }
  191.         }
  192.         $this->logger->invalidate($tags);
  193.     }
  194.     public function invalidateShippingMethodRoute(EntityWrittenContainerEvent $event): void
  195.     {
  196.         // checks if a shipping method changed or the assignment between shipping method and sales channel
  197.         $logs array_merge(
  198.             $this->getChangedShippingMethods($event),
  199.             $this->getChangedShippingAssignments($event)
  200.         );
  201.         $this->logger->invalidate($logs);
  202.     }
  203.     public function invalidateSeoUrls(SeoUrlUpdateEvent $event): void
  204.     {
  205.         // invalidates the cache for the seo url resolver based on the path infos which used for the new seo urls
  206.         $urls $event->getSeoUrls();
  207.         $pathInfo array_column($urls'pathInfo');
  208.         $this->logger->invalidate(array_map([CachedSeoResolver::class, 'buildName'], $pathInfo));
  209.     }
  210.     public function invalidateRules(): void
  211.     {
  212.         // invalidates the rule loader each time a rule changed or a plugin install state changed
  213.         $this->logger->invalidate([CachedRuleLoader::CACHE_KEY]);
  214.     }
  215.     public function invalidateCmsPageIds(EntityWrittenContainerEvent $event): void
  216.     {
  217.         // invalidates all routes and http cache pages where a cms page was loaded, the id is assigned as tag
  218.         $this->logger->invalidate(
  219.             array_map([EntityCacheKeyGenerator::class, 'buildCmsTag'], $event->getPrimaryKeys(CmsPageDefinition::ENTITY_NAME))
  220.         );
  221.     }
  222.     public function invalidateProductIds(ProductChangedEventInterface $event): void
  223.     {
  224.         // invalidates all routes which loads products in nested unknown objects, like cms listing elements or cross selling elements
  225.         $this->logger->invalidate(
  226.             array_map([EntityCacheKeyGenerator::class, 'buildProductTag'], $event->getIds())
  227.         );
  228.     }
  229.     public function invalidateStreamIds(EntityWrittenContainerEvent $event): void
  230.     {
  231.         // invalidates all routes which are loaded based on a stream (e.G. category listing and cross selling)
  232.         $this->logger->invalidate(
  233.             array_map([EntityCacheKeyGenerator::class, 'buildStreamTag'], $event->getPrimaryKeys(ProductStreamDefinition::ENTITY_NAME))
  234.         );
  235.     }
  236.     public function invalidateCategoryRouteByCategoryIds(CategoryIndexerEvent $event): void
  237.     {
  238.         // invalidates the category route cache when a category changed
  239.         $this->logger->invalidate(
  240.             array_map([CachedCategoryRoute::class, 'buildName'], $event->getIds())
  241.         );
  242.     }
  243.     public function invalidateListingRouteByCategoryIds(CategoryIndexerEvent $event): void
  244.     {
  245.         // invalidates the product listing route each time a category changed
  246.         $this->logger->invalidate(
  247.             array_map([CachedProductListingRoute::class, 'buildName'], $event->getIds())
  248.         );
  249.     }
  250.     public function invalidateIndexedLandingPages(LandingPageIndexerEvent $event): void
  251.     {
  252.         // invalidates the landing page route, if the corresponding landing page changed
  253.         $this->logger->invalidate(
  254.             array_map([CachedLandingPageRoute::class, 'buildName'], $event->getIds())
  255.         );
  256.     }
  257.     public function invalidateCurrencyRoute(EntityWrittenContainerEvent $event): void
  258.     {
  259.         // invalidates the currency route when a currency changed or an assignment between the sales channel and currency changed
  260.         $this->logger->invalidate(array_merge(
  261.             $this->getChangedCurrencyAssignments($event),
  262.             $this->getChangedCurrencies($event)
  263.         ));
  264.     }
  265.     public function invalidateLanguageRoute(EntityWrittenContainerEvent $event): void
  266.     {
  267.         // invalidates the language route when a language changed or an assignment between the sales channel and language changed
  268.         $this->logger->invalidate(array_merge(
  269.             $this->getChangedLanguageAssignments($event),
  270.             $this->getChangedLanguages($event)
  271.         ));
  272.     }
  273.     public function invalidateCountryRoute(EntityWrittenContainerEvent $event): void
  274.     {
  275.         // invalidates the country route when a country changed or an assignment between the sales channel and country changed
  276.         $this->logger->invalidate(array_merge(
  277.             $this->getChangedCountryAssignments($event),
  278.             $this->getChangedCountries($event),
  279.         ));
  280.     }
  281.     public function invalidateSalutationRoute(EntityWrittenContainerEvent $event): void
  282.     {
  283.         // invalidates the salutation route when a salutation changed
  284.         $this->logger->invalidate(array_merge(
  285.             $this->getChangedSalutations($event),
  286.         ));
  287.     }
  288.     public function invalidateNavigationRoute(EntityWrittenContainerEvent $event): void
  289.     {
  290.         // invalidates the navigation route when a category changed or the entry point configuration of an sales channel changed
  291.         $logs array_merge(
  292.             $this->getChangedCategories($event),
  293.             $this->getChangedEntryPoints($event)
  294.         );
  295.         $this->logger->invalidate($logs);
  296.     }
  297.     public function invalidatePaymentMethodRoute(EntityWrittenContainerEvent $event): void
  298.     {
  299.         // invalidates the payment method route when a payment method changed or an assignment between the sales channel and payment method changed
  300.         $logs array_merge(
  301.             $this->getChangedPaymentMethods($event),
  302.             $this->getChangedPaymentAssignments($event)
  303.         );
  304.         $this->logger->invalidate($logs);
  305.     }
  306.     public function invalidateSearch(): void
  307.     {
  308.         // invalidates the search and suggest route each time a product changed
  309.         $this->logger->invalidate([
  310.             'product-suggest-route',
  311.             'product-search-route',
  312.         ]);
  313.     }
  314.     public function invalidateDetailRoute(ProductChangedEventInterface $event): void
  315.     {
  316.         //invalidates the product detail route each time a product changed or if the product is no longer available (because out of stock)
  317.         $this->logger->invalidate(
  318.             array_map([CachedProductDetailRoute::class, 'buildName'], $event->getIds())
  319.         );
  320.     }
  321.     public function invalidateProductAssignment(EntityWrittenContainerEvent $event): void
  322.     {
  323.         //invalidates the product listing route, each time a product - category assignment changed
  324.         $ids $event->getPrimaryKeys(ProductCategoryDefinition::ENTITY_NAME);
  325.         $ids array_column($ids'categoryId');
  326.         $this->logger->invalidate(
  327.             array_map([CachedProductListingRoute::class, 'buildName'], $ids)
  328.         );
  329.     }
  330.     public function invalidateContext(EntityWrittenContainerEvent $event): void
  331.     {
  332.         //invalidates the context cache - each time one of the entities which are considered inside the context factory changed
  333.         $ids $event->getPrimaryKeys(SalesChannelDefinition::ENTITY_NAME);
  334.         $keys array_map([CachedSalesChannelContextFactory::class, 'buildName'], $ids);
  335.         if ($event->getEventByEntityName(CurrencyDefinition::ENTITY_NAME)) {
  336.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  337.         }
  338.         if ($event->getEventByEntityName(PaymentMethodDefinition::ENTITY_NAME)) {
  339.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  340.         }
  341.         if ($event->getEventByEntityName(ShippingMethodDefinition::ENTITY_NAME)) {
  342.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  343.         }
  344.         if ($event->getEventByEntityName(TaxDefinition::ENTITY_NAME)) {
  345.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  346.         }
  347.         if ($event->getEventByEntityName(CountryDefinition::ENTITY_NAME)) {
  348.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  349.         }
  350.         if ($event->getEventByEntityName(CustomerGroupDefinition::ENTITY_NAME)) {
  351.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  352.         }
  353.         if ($event->getEventByEntityName(LanguageDefinition::ENTITY_NAME)) {
  354.             $keys[] = CachedSalesChannelContextFactory::ALL_TAG;
  355.         }
  356.         $keys array_filter(array_unique($keys));
  357.         if (empty($keys)) {
  358.             return;
  359.         }
  360.         $this->logger->invalidate($keys);
  361.     }
  362.     public function invalidateManufacturerFilters(EntityWrittenContainerEvent $event): void
  363.     {
  364.         // invalidates the product listing route, each time a manufacturer changed
  365.         $ids $event->getPrimaryKeys(ProductManufacturerDefinition::ENTITY_NAME);
  366.         if (empty($ids)) {
  367.             return;
  368.         }
  369.         $ids $this->connection->fetchFirstColumn(
  370.             'SELECT DISTINCT LOWER(HEX(category_id)) as category_id
  371.              FROM product_category_tree
  372.                 INNER JOIN product ON product.id = product_category_tree.product_id AND product_category_tree.product_version_id = product.version_id
  373.              WHERE product.product_manufacturer_id IN (:ids)
  374.              AND product.version_id = :version',
  375.             ['ids' => Uuid::fromHexToBytesList($ids), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  376.             ['ids' => Connection::PARAM_STR_ARRAY]
  377.         );
  378.         $this->logger->invalidate(
  379.             array_map([CachedProductListingRoute::class, 'buildName'], $ids)
  380.         );
  381.     }
  382.     public function invalidatePropertyFilters(EntityWrittenContainerEvent $event): void
  383.     {
  384.         // invalidates the product listing route, each time a property changed
  385.         $ids $event->getPrimaryKeys(PropertyGroupDefinition::ENTITY_NAME);
  386.         if (empty($ids)) {
  387.             return;
  388.         }
  389.         $ids $this->connection->fetchFirstColumn(
  390.             'SELECT DISTINCT LOWER(HEX(category_id)) as category_id
  391.              FROM product_category_tree
  392.                 INNER JOIN product_property ON product_category_tree.product_id = product_property.product_id AND product_category_tree.product_version_id = product_property.product_version_id
  393.                 INNER JOIN property_group_option ON property_group_option.id = product_property.property_group_option_id
  394.              WHERE property_group_option.property_group_id IN (:ids)
  395.              AND product_category_tree.product_version_id = :version',
  396.             ['ids' => Uuid::fromHexToBytesList($ids), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  397.             ['ids' => Connection::PARAM_STR_ARRAY]
  398.         );
  399.         $this->logger->invalidate(
  400.             array_map([CachedProductListingRoute::class, 'buildName'], $ids)
  401.         );
  402.     }
  403.     public function invalidateReviewRoute(ProductChangedEventInterface $event): void
  404.     {
  405.         $this->logger->invalidate(
  406.             array_map([CachedProductReviewRoute::class, 'buildName'], $event->getIds())
  407.         );
  408.     }
  409.     public function invalidateListings(ProductChangedEventInterface $event): void
  410.     {
  411.         // invalidates product listings which are based on the product category assignment
  412.         $ids $this->connection->fetchFirstColumn(
  413.             'SELECT DISTINCT LOWER(HEX(category_id)) as category_id
  414.              FROM product_category_tree
  415.              WHERE product_id IN (:ids)
  416.              AND product_version_id = :version
  417.              AND category_version_id = :version',
  418.             ['ids' => Uuid::fromHexToBytesList($event->getIds()), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  419.             ['ids' => Connection::PARAM_STR_ARRAY]
  420.         );
  421.         $this->logger->invalidate(
  422.             array_map([CachedProductListingRoute::class, 'buildName'], $ids)
  423.         );
  424.     }
  425.     public function invalidateStreamsBeforeIndexing(EntityWrittenContainerEvent $event): void
  426.     {
  427.         // invalidates all stream based pages and routes before the product indexer changes product_stream_mapping
  428.         $ids $event->getPrimaryKeys(ProductDefinition::ENTITY_NAME);
  429.         if (empty($ids)) {
  430.             return;
  431.         }
  432.         // invalidates product listings which are based on a product stream
  433.         $ids $this->connection->fetchFirstColumn(
  434.             'SELECT DISTINCT LOWER(HEX(product_stream_id))
  435.              FROM product_stream_mapping
  436.              WHERE product_stream_mapping.product_id IN (:ids)
  437.              AND product_stream_mapping.product_version_id = :version',
  438.             ['ids' => Uuid::fromHexToBytesList($ids), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  439.             ['ids' => Connection::PARAM_STR_ARRAY]
  440.         );
  441.         $this->logger->invalidate(
  442.             array_map([EntityCacheKeyGenerator::class, 'buildStreamTag'], $ids)
  443.         );
  444.     }
  445.     public function invalidateStreamsAfterIndexing(ProductChangedEventInterface $event): void
  446.     {
  447.         // invalidates all stream based pages and routes after the product indexer changes product_stream_mapping
  448.         $ids $this->connection->fetchFirstColumn(
  449.             'SELECT DISTINCT LOWER(HEX(product_stream_id))
  450.              FROM product_stream_mapping
  451.              WHERE product_stream_mapping.product_id IN (:ids)
  452.              AND product_stream_mapping.product_version_id = :version',
  453.             ['ids' => Uuid::fromHexToBytesList($event->getIds()), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  454.             ['ids' => Connection::PARAM_STR_ARRAY]
  455.         );
  456.         $this->logger->invalidate(
  457.             array_map([EntityCacheKeyGenerator::class, 'buildStreamTag'], $ids)
  458.         );
  459.     }
  460.     public function invalidateCrossSellingRoute(EntityWrittenContainerEvent $event): void
  461.     {
  462.         // invalidates the product detail route for the changed cross selling definitions
  463.         $ids $event->getPrimaryKeys(ProductCrossSellingDefinition::ENTITY_NAME);
  464.         if (empty($ids)) {
  465.             return;
  466.         }
  467.         $ids $this->connection->fetchFirstColumn(
  468.             'SELECT DISTINCT LOWER(HEX(product_id)) FROM product_cross_selling WHERE id IN (:ids)',
  469.             ['ids' => Uuid::fromHexToBytesList($ids)],
  470.             ['ids' => Connection::PARAM_STR_ARRAY]
  471.         );
  472.         $this->logger->invalidate(
  473.             array_map([CachedProductCrossSellingRoute::class, 'buildName'], $ids)
  474.         );
  475.     }
  476.     private function getChangedShippingMethods(EntityWrittenContainerEvent $event): array
  477.     {
  478.         $ids $event->getPrimaryKeys(ShippingMethodDefinition::ENTITY_NAME);
  479.         if (empty($ids)) {
  480.             return [];
  481.         }
  482.         $ids $this->connection->fetchFirstColumn(
  483.             'SELECT DISTINCT LOWER(HEX(sales_channel_id)) as id FROM sales_channel_shipping_method WHERE shipping_method_id IN (:ids)',
  484.             ['ids' => Uuid::fromHexToBytesList($ids)],
  485.             ['ids' => Connection::PARAM_STR_ARRAY]
  486.         );
  487.         return array_map([CachedShippingMethodRoute::class, 'buildName'], $ids);
  488.     }
  489.     private function getChangedShippingAssignments(EntityWrittenContainerEvent $event): array
  490.     {
  491.         //Used to detect changes to the shipping assignment of a sales channel
  492.         $ids $event->getPrimaryKeys(SalesChannelShippingMethodDefinition::ENTITY_NAME);
  493.         $ids array_column($ids'salesChannelId');
  494.         return array_map([CachedShippingMethodRoute::class, 'buildName'], $ids);
  495.     }
  496.     private function getChangedPaymentMethods(EntityWrittenContainerEvent $event): array
  497.     {
  498.         $ids $event->getPrimaryKeys(PaymentMethodDefinition::ENTITY_NAME);
  499.         if (empty($ids)) {
  500.             return [];
  501.         }
  502.         $ids $this->connection->fetchFirstColumn(
  503.             'SELECT DISTINCT LOWER(HEX(sales_channel_id)) as id FROM sales_channel_payment_method WHERE payment_method_id IN (:ids)',
  504.             ['ids' => Uuid::fromHexToBytesList($ids)],
  505.             ['ids' => Connection::PARAM_STR_ARRAY]
  506.         );
  507.         return array_map([CachedPaymentMethodRoute::class, 'buildName'], $ids);
  508.     }
  509.     private function getChangedPaymentAssignments(EntityWrittenContainerEvent $event): array
  510.     {
  511.         //Used to detect changes to the language assignment of a sales channel
  512.         $ids $event->getPrimaryKeys(SalesChannelPaymentMethodDefinition::ENTITY_NAME);
  513.         $ids array_column($ids'salesChannelId');
  514.         return array_map([CachedPaymentMethodRoute::class, 'buildName'], $ids);
  515.     }
  516.     private function getChangedCategories(EntityWrittenContainerEvent $event): array
  517.     {
  518.         $ids $event->getPrimaryKeysWithPayload(CategoryDefinition::ENTITY_NAME);
  519.         if (empty($ids)) {
  520.             return [];
  521.         }
  522.         $ids array_map([CachedNavigationRoute::class, 'buildName'], $ids);
  523.         $ids[] = CachedNavigationRoute::BASE_NAVIGATION_TAG;
  524.         return $ids;
  525.     }
  526.     private function getChangedEntryPoints(EntityWrittenContainerEvent $event): array
  527.     {
  528.         $ids $event->getPrimaryKeysWithPropertyChange(
  529.             SalesChannelDefinition::ENTITY_NAME,
  530.             ['navigationCategoryId''navigationCategoryDepth''serviceCategoryId''footerCategoryId']
  531.         );
  532.         if (empty($ids)) {
  533.             return [];
  534.         }
  535.         return [CachedNavigationRoute::ALL_TAG];
  536.     }
  537.     private function getChangedCountries(EntityWrittenContainerEvent $event): array
  538.     {
  539.         $ids $event->getPrimaryKeys(CountryDefinition::ENTITY_NAME);
  540.         if (empty($ids)) {
  541.             return [];
  542.         }
  543.         //Used to detect changes to the country itself and invalidate the route for all sales channels in which the country is assigned.
  544.         $ids $this->connection->fetchFirstColumn(
  545.             'SELECT DISTINCT LOWER(HEX(sales_channel_id)) as id FROM sales_channel_country WHERE country_id IN (:ids)',
  546.             ['ids' => Uuid::fromHexToBytesList($ids)],
  547.             ['ids' => Connection::PARAM_STR_ARRAY]
  548.         );
  549.         $tags = [];
  550.         if ($event->getDeletedPrimaryKeys(CountryDefinition::ENTITY_NAME)) {
  551.             $tags[] = CachedCountryRoute::ALL_TAG;
  552.         }
  553.         return array_merge($tagsarray_map([CachedCountryRoute::class, 'buildName'], $ids));
  554.     }
  555.     private function getChangedCountryAssignments(EntityWrittenContainerEvent $event): array
  556.     {
  557.         //Used to detect changes to the country assignment of a sales channel
  558.         $ids $event->getPrimaryKeys(SalesChannelCountryDefinition::ENTITY_NAME);
  559.         $ids array_column($ids'salesChannelId');
  560.         return array_map([CachedCountryRoute::class, 'buildName'], $ids);
  561.     }
  562.     private function getChangedSalutations(EntityWrittenContainerEvent $event): array
  563.     {
  564.         $ids $event->getPrimaryKeys(SalutationDefinition::ENTITY_NAME);
  565.         if (empty($ids)) {
  566.             return [];
  567.         }
  568.         return [CachedSalutationRoute::ALL_TAG];
  569.     }
  570.     private function getChangedLanguages(EntityWrittenContainerEvent $event): array
  571.     {
  572.         $ids $event->getPrimaryKeys(LanguageDefinition::ENTITY_NAME);
  573.         if (empty($ids)) {
  574.             return [];
  575.         }
  576.         //Used to detect changes to the language itself and invalidate the route for all sales channels in which the language is assigned.
  577.         $ids $this->connection->fetchFirstColumn(
  578.             'SELECT DISTINCT LOWER(HEX(sales_channel_id)) as id FROM sales_channel_language WHERE language_id IN (:ids)',
  579.             ['ids' => Uuid::fromHexToBytesList($ids)],
  580.             ['ids' => Connection::PARAM_STR_ARRAY]
  581.         );
  582.         return array_map([CachedLanguageRoute::class, 'buildName'], $ids);
  583.     }
  584.     private function getChangedLanguageAssignments(EntityWrittenContainerEvent $event): array
  585.     {
  586.         //Used to detect changes to the language assignment of a sales channel
  587.         $ids $event->getPrimaryKeys(SalesChannelLanguageDefinition::ENTITY_NAME);
  588.         $ids array_column($ids'salesChannelId');
  589.         return array_map([CachedLanguageRoute::class, 'buildName'], $ids);
  590.     }
  591.     private function getChangedCurrencies(EntityWrittenContainerEvent $event): array
  592.     {
  593.         $ids $event->getPrimaryKeys(CurrencyDefinition::ENTITY_NAME);
  594.         if (empty($ids)) {
  595.             return [];
  596.         }
  597.         //Used to detect changes to the currency itself and invalidate the route for all sales channels in which the currency is assigned.
  598.         $ids $this->connection->fetchFirstColumn(
  599.             'SELECT DISTINCT LOWER(HEX(sales_channel_id)) as id FROM sales_channel_currency WHERE currency_id IN (:ids)',
  600.             ['ids' => Uuid::fromHexToBytesList($ids)],
  601.             ['ids' => Connection::PARAM_STR_ARRAY]
  602.         );
  603.         return array_map([CachedCurrencyRoute::class, 'buildName'], $ids);
  604.     }
  605.     private function getChangedCurrencyAssignments(EntityWrittenContainerEvent $event): array
  606.     {
  607.         //Used to detect changes to the currency assignment of a sales channel
  608.         $ids $event->getPrimaryKeys(SalesChannelCurrencyDefinition::ENTITY_NAME);
  609.         $ids array_column($ids'salesChannelId');
  610.         return array_map([CachedCurrencyRoute::class, 'buildName'], $ids);
  611.     }
  612. }