diff --git a/src/module-elasticsuite-virtual-category/Helper/Rule.php b/src/module-elasticsuite-virtual-category/Helper/Rule.php index aa2d72b5d..b65e744f3 100644 --- a/src/module-elasticsuite-virtual-category/Helper/Rule.php +++ b/src/module-elasticsuite-virtual-category/Helper/Rule.php @@ -47,6 +47,11 @@ class Rule */ private $categoryRepository; + /** + * @var Config + */ + private $config; + /** * Provider constructor. * @@ -54,17 +59,20 @@ class Rule * @param \Magento\Customer\Model\Session $customerSession Customer session. * @param ReadHandler $readHandler Rule read handler. * @param \Magento\Catalog\Api\CategoryRepositoryInterfaceFactory $categoryRepository Category factory. + * @param Config $config Virtual category configuration. */ public function __construct( \Magento\Framework\App\CacheInterface $cache, \Magento\Customer\Model\Session $customerSession, ReadHandler $readHandler, - CategoryRepositoryInterfaceFactory $categoryRepository + CategoryRepositoryInterfaceFactory $categoryRepository, + Config $config ) { $this->cache = $cache; $this->customerSession = $customerSession; $this->readHandler = $readHandler; $this->categoryRepository = $categoryRepository; + $this->config = $config; } /** @@ -79,7 +87,16 @@ public function __construct( public function loadUsingCache(CategoryInterface $category, $callback) { \Magento\Framework\Profiler::start('ES:Virtual Rule ' . $callback); - $cacheKey = implode('|', [$callback, $category->getStoreId(), $category->getId(), $this->customerSession->getCustomerGroupId()]); + $cacheKey = implode( + '|', + [ + $callback, + $category->getStoreId(), + $category->getId(), + $this->customerSession->getCustomerGroupId(), + (int) $this->config->isForceZeroResultsForDisabledCategoriesEnabled($category->getStoreId()), + ] + ); $data = $this->cache->load($cacheKey); diff --git a/src/module-elasticsuite-virtual-category/Model/Rule.php b/src/module-elasticsuite-virtual-category/Model/Rule.php index 0c1687410..cdc78bf70 100644 --- a/src/module-elasticsuite-virtual-category/Model/Rule.php +++ b/src/module-elasticsuite-virtual-category/Model/Rule.php @@ -189,6 +189,7 @@ public function getCategorySearchQuery($category, $excludedCategories = []): ?Qu \Magento\Framework\Profiler::start('ES:Virtual Rule ' . __FUNCTION__); $categoryId = (int) (!is_object($category) ? $category : $category->getId()); $storeId = !is_object($category) ? $this->getStoreId() : $category->getStoreId(); + $storeId = $storeId ?: $this->storeManager->getStore()->getId(); $cacheKey = implode( '|', [ @@ -196,7 +197,7 @@ public function getCategorySearchQuery($category, $excludedCategories = []): ?Qu $storeId, $categoryId, $this->customerSession->getCustomerGroupId(), - $this->config->isForceZeroResultsForDisabledCategoriesEnabled($storeId), + (int) $this->config->isForceZeroResultsForDisabledCategoriesEnabled($storeId), ] ); @@ -204,10 +205,14 @@ public function getCategorySearchQuery($category, $excludedCategories = []): ?Qu // If the category is not an object, it can't be in a "draft" mode. if ($query === false && (!is_object($category) || !$category->getHasDraftVirtualRule())) { - // Due to the fact we serialize/unserialize completely pre-built queries as object. - // We cannot use any implementation of SerializerInterface. - $query = $this->sharedCache->load($cacheKey); - $query = $query ? unserialize($query) : false; + // If the category virtual root is one of the excluded categories, we must recalculate the query. + // We can't use the cached one in order to avoid loop and very big queries. + if (!is_object($category) || !$this->isVirtualCategoryRootInExcludeCategories($category, $excludedCategories)) { + // Due to the fact we serialize/unserialize completely pre-built queries as object. + // We cannot use any implementation of SerializerInterface. + $query = $this->sharedCache->load($cacheKey); + $query = $query ? unserialize($query) : false; + } } if ($query === false) { @@ -439,23 +444,11 @@ private function getVirtualCategoryQuery( CategoryInterface $category, $excludedCategories = [] ): ?QueryInterface { - $rootCategory = $this->getVirtualRootCategory($category); - // If the root category of the current virtual category has already been computed (exist in $excludedCategories) - // or if a parent of the root category of the current category has already been computed we don't need - // to compute the rule. All the product will already been present. - // For example, if you have the following category tree: - // - Category A (static) - // - - Category B (static) - // - - Category C (virtual with category B as root) - // When you compute the rule of the category A you do not need to compute the rule of the category C - // as all the product will be there. - if ($rootCategory - && $rootCategory->getPath() - && array_intersect(explode('/', (string) $rootCategory->getPath()), $excludedCategories) - ) { + if ($this->isVirtualCategoryRootInExcludeCategories($category, $excludedCategories)) { return null; } + $rootCategory = $this->getVirtualRootCategory($category); $query = $category->getVirtualRule()->getConditions()->getSearchQuery($excludedCategories); if ($query instanceof QueryInterface) { $queryName = sprintf('(%s) virtual category [%s]:%d', $category->getPath(), $category->getName(), $category->getId()); @@ -630,4 +623,30 @@ private function getNoResultsQuery(): QueryInterface ['field' => 'entity_id', 'values' => [0]] ); } + + /** + * If the root category of the current virtual category has already been computed (exist in $excludedCategories) + * or if a parent of the root category of the current category has already been computed we don't need + * to compute the rule. All the product will already been present. + * For example, if you have the following category tree: + * - Category A (static) + * - - Category B (static) + * - - Category C (virtual with category B as root) + * When you compute the rule of the category A you do not need to compute the rule of the category C + * as all the product will be there. + * + * @param CategoryInterface $category category to check + * @param array $excludedCategories list of actual excluded categories + * @return bool + * @throws NoSuchEntityException + */ + private function isVirtualCategoryRootInExcludeCategories(CategoryInterface $category, array $excludedCategories): bool + { + $rootCategory = $this->getVirtualRootCategory($category); + + return $category->getIsVirtualCategory() + && $rootCategory + && $rootCategory->getPath() + && array_intersect(explode('/', (string) $rootCategory->getPath()), $excludedCategories); + } }