From 1779ffe2ba26ad7364c387954e991d8f7f3badd2 Mon Sep 17 00:00:00 2001 From: Richard BAYET Date: Tue, 30 Oct 2018 19:37:25 +0100 Subject: [PATCH] Fixes #1153 Reducing list of filterable attributes to those relevant for the currently assigned products --- .../Category/Collection.php | 31 +++++ .../Ui/Category/Form/DataProviderPlugin.php | 116 +++++++++++++++++- 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/src/module-elasticsuite-catalog/Model/ResourceModel/Product/FilterableAttribute/Category/Collection.php b/src/module-elasticsuite-catalog/Model/ResourceModel/Product/FilterableAttribute/Category/Collection.php index 433d952a7..fdc0aa207 100644 --- a/src/module-elasticsuite-catalog/Model/ResourceModel/Product/FilterableAttribute/Category/Collection.php +++ b/src/module-elasticsuite-catalog/Model/ResourceModel/Product/FilterableAttribute/Category/Collection.php @@ -68,6 +68,37 @@ public function applyCategory() return $this; } + /** + * Specify attribute set filter + * + * @param array|int $setId Attribute Set Id(s) + * + * @return $this + */ + public function setAttributeSetFilter($setId) + { + if (is_array($setId)) { + if (!empty($setId)) { + $this->join( + ['entity_attribute' => $this->getTable('eav_entity_attribute')], + 'entity_attribute.attribute_id = main_table.attribute_id', + [] + ); + $this->addFieldToFilter('entity_attribute.attribute_set_id', ['in' => $setId]); + $this->addAttributeGrouping(); + } + } elseif ($setId) { + $this->join( + ['entity_attribute' => $this->getTable('eav_entity_attribute')], + 'entity_attribute.attribute_id = main_table.attribute_id', + [] + ); + $this->addFieldToFilter('entity_attribute.attribute_set_id', $setId); + } + + return $this; + } + /** * @SuppressWarnings(PHPMD.CamelCaseMethodName) * diff --git a/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php b/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php index c8e41738a..d3b7517a6 100644 --- a/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php +++ b/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php @@ -15,6 +15,11 @@ use Magento\Catalog\Api\Data\CategoryInterface; use Smile\ElasticsuiteCatalog\Model\Attribute\Source\FilterDisplayMode; use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\FilterableAttribute\Category\CollectionFactory as AttributeCollectionFactory; +use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\CollectionFactory as FulltextCollectionFactory; +use Magento\Store\Model\StoreManagerInterface; +use Smile\ElasticsuiteCore\Search\Request\QueryInterface; +use Smile\ElasticsuiteCore\Api\Search\ContextInterface; +use Smile\ElasticsuiteCore\Search\Request\Query\Builder as QueryBuilder; use Magento\Catalog\Model\Category\DataProvider as CategoryDataProvider; @@ -32,14 +37,39 @@ class DataProviderPlugin */ private $attributeCollectionFactory; + /** + * @var FulltextCollectionFactory + */ + private $fulltextCollectionFactory; + + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + + /** + * @var \Smile\ElasticsuiteCore\Api\Search\ContextInterface + */ + private $searchContext; + /** * DataProviderPlugin constructor. * - * @param AttributeCollectionFactory $attributeCollectionFactory Attribute Collection Factory. + * @param AttributeCollectionFactory $attributeCollectionFactory Attribute Collection Factory. + * @param FulltextCollectionFactory $fulltextCollectionFactory Fulltext Collection Factory. + * @param StoreManagerInterface $storeManager Store Manager. + * @param ContextInterface $searchContext Search context. */ - public function __construct(AttributeCollectionFactory $attributeCollectionFactory) - { + public function __construct( + AttributeCollectionFactory $attributeCollectionFactory, + FulltextCollectionFactory $fulltextCollectionFactory, + StoreManagerInterface $storeManager, + ContextInterface $searchContext + ) { $this->attributeCollectionFactory = $attributeCollectionFactory; + $this->fulltextCollectionFactory = $fulltextCollectionFactory; + $this->storeManager = $storeManager; + $this->searchContext = $searchContext; } /** @@ -117,7 +147,67 @@ private function getFilterableAttributeList($currentCategory) } /** - * Retrieve attribute collection pre-filtered with only attribute filterable. + * Retrieve default store view id. + * + * @return int + */ + private function getDefaultStoreId() + { + $store = $this->storeManager->getDefaultStoreView(); + + if (null === $store) { + // Occurs when current user does not have access to default website (due to AdminGWS ACLS on Magento EE). + $store = !empty($this->storeManager->getWebsites()) ? current($this->storeManager->getWebsites())->getDefaultStore() : null; + } + + return $store ? $store->getId() : 0; + } + + /** + * Get store id for the current category. + * + * @param CategoryInterface $category Category. + * + * @return int + */ + private function getStoreId(CategoryInterface $category) + { + $storeId = $category->getStoreId(); + + if ($storeId === 0) { + $defaultStoreId = $this->getDefaultStoreId(); + $categoryStoreIds = array_filter($category->getStoreIds()); + $storeId = current($categoryStoreIds); + if (in_array($defaultStoreId, $categoryStoreIds)) { + $storeId = $defaultStoreId; + } + } + + return $storeId; + } + + /** + * Return category filter param + * + * @param CategoryInterface $category Category. + * + * @return int|QueryInterface + */ + private function getCategoryFilterParam(CategoryInterface $category) + { + $filterParam = $category->getId(); + + if ($category->getVirtualRule()) { // Implicit dependency to Virtual Categories module. + $category->setIsActive(true); + + $filterParam = $category->getVirtualRule()->getCategorySearchQuery($category); + } + + return $filterParam; + } + + /** + * Retrieve attribute collection pre-filtered with only filterable attributes. * * @param CategoryInterface $category Category * @@ -132,6 +222,24 @@ private function getAttributes($category) ->addStoreLabel($category->getStoreId()) ->setOrder('position', 'ASC'); + $storeId = $this->getStoreId($category); + + if ($storeId && $category->getId()) { + // Make a side effect on the context that will be used by the fulltext collection's request builder. + $this->searchContext->setCurrentCategory($category) + ->setStoreId($storeId); + + /** @var \Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection $fulltextCollection */ + $fulltextCollection = $this->fulltextCollectionFactory->create(); + $fulltextCollection->setStoreId($storeId) + ->addFieldToFilter('category_ids', $this->getCategoryFilterParam($category)); + + $attributeSetIds = array_keys($fulltextCollection->getProductCountByAttributeSetId()); + if (!empty($attributeSetIds)) { + $collection->setAttributeSetFilter($attributeSetIds); + } + } + return $collection->getItems(); } }