From 58983db679982cdb7f7cf5d0027ec705973e1431 Mon Sep 17 00:00:00 2001 From: Botis Date: Wed, 6 Oct 2021 16:17:50 +0200 Subject: [PATCH] #ESP-252 Add layered navigation attributes management * Add layered navigation attributes management * Add No value filter for boolean * Fix applying boolean filters on GraphQL --- .../LayeredNavigation/Builder/Attribute.php | 22 ++-- .../etc/graphql/di.xml | 5 + .../Rule/Condition/Product/AttributeList.php | 44 +++++--- .../Api/LayeredNavAttributeInterface.php | 53 ++++++++++ .../LayeredNavAttributesProvider.php | 100 ++++++++++++++++++ .../Model/Layer/Filter/Boolean.php | 88 ++++++++++++--- .../Model/Layer/Filter/Item/Attribute.php | 2 +- .../Aggregation/LayeredNavAttribute.php | 68 ++++++++++++ .../Plugin/Search/RequestMapperPlugin.php | 84 ++++++++++++--- .../Modifier/Coverage.php | 28 +++-- .../etc/frontend/di.xml | 17 +-- 11 files changed, 448 insertions(+), 63 deletions(-) create mode 100644 src/module-elasticsuite-catalog/Api/LayeredNavAttributeInterface.php create mode 100644 src/module-elasticsuite-catalog/Model/Attribute/LayeredNavAttributesProvider.php create mode 100644 src/module-elasticsuite-catalog/Plugin/Search/Request/Product/Attribute/Aggregation/LayeredNavAttribute.php diff --git a/src/module-elasticsuite-catalog-graph-ql/DataProvider/Product/LayeredNavigation/Builder/Attribute.php b/src/module-elasticsuite-catalog-graph-ql/DataProvider/Product/LayeredNavigation/Builder/Attribute.php index 1d562b9a4..69dace4f8 100644 --- a/src/module-elasticsuite-catalog-graph-ql/DataProvider/Product/LayeredNavigation/Builder/Attribute.php +++ b/src/module-elasticsuite-catalog-graph-ql/DataProvider/Product/LayeredNavigation/Builder/Attribute.php @@ -21,6 +21,7 @@ use Magento\Framework\Api\Search\BucketInterface; use Smile\ElasticsuiteCore\Helper\Mapping; use Smile\ElasticsuiteCore\Search\Request\BucketInterface as ElasticBucketInterface; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; /** * Layered Navigation Builder for Default Attribute. @@ -41,6 +42,11 @@ class Attribute implements LayerBuilderInterface */ private $attributeRepository; + /** + * @var LayeredNavAttributesProvider + */ + protected $layeredNavAttributesProvider; + /** * @var array */ @@ -50,18 +56,21 @@ class Attribute implements LayerBuilderInterface ]; /** - * @param LayerFormatter $layerFormatter Layer Formatter - * @param AttributeRepository $attributeRepository Attribute Repository - * @param array $bucketNameFilter Bucket Filter + * @param LayerFormatter $layerFormatter Layer Formatter. + * @param AttributeRepository $attributeRepository Attribute Repository. + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered nav attributes provider. + * @param array $bucketNameFilter Bucket Filter. */ public function __construct( LayerFormatter $layerFormatter, AttributeRepository $attributeRepository, + LayeredNavAttributesProvider $layeredNavAttributesProvider, $bucketNameFilter = [] ) { - $this->layerFormatter = $layerFormatter; - $this->bucketNameFilter = \array_merge($this->bucketNameFilter, $bucketNameFilter); - $this->attributeRepository = $attributeRepository; + $this->layerFormatter = $layerFormatter; + $this->bucketNameFilter = \array_merge($this->bucketNameFilter, $bucketNameFilter); + $this->attributeRepository = $attributeRepository; + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; } /** @@ -80,6 +89,7 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array if (substr($bucketName, 0, strlen($prefix)) === $prefix) { $attributeCode = substr($bucketName, strlen($prefix)); } + $attributeCode = $this->layeredNavAttributesProvider->getLayeredNavAttributeByFilterField($bucketName) ?? $attributeCode; $label = $attributeCode; try { diff --git a/src/module-elasticsuite-catalog-graph-ql/etc/graphql/di.xml b/src/module-elasticsuite-catalog-graph-ql/etc/graphql/di.xml index a463beb4b..fd76654da 100644 --- a/src/module-elasticsuite-catalog-graph-ql/etc/graphql/di.xml +++ b/src/module-elasticsuite-catalog-graph-ql/etc/graphql/di.xml @@ -139,4 +139,9 @@ + + + + diff --git a/src/module-elasticsuite-catalog-rule/Model/Rule/Condition/Product/AttributeList.php b/src/module-elasticsuite-catalog-rule/Model/Rule/Condition/Product/AttributeList.php index e014c09dd..ec50a3970 100644 --- a/src/module-elasticsuite-catalog-rule/Model/Rule/Condition/Product/AttributeList.php +++ b/src/module-elasticsuite-catalog-rule/Model/Rule/Condition/Product/AttributeList.php @@ -20,6 +20,7 @@ use Smile\ElasticsuiteCore\Api\Index\Mapping\FieldInterface; use Smile\ElasticsuiteCore\Api\Index\MappingInterface; use Smile\ElasticsuiteCore\Helper\Mapping as MappingHelper; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; /** * List of attributes used in query building. @@ -75,16 +76,22 @@ class AttributeList */ private $requestFieldMapper; + /** + * @var LayeredNavAttributesProvider + */ + private $layeredNavAttributesProvider; + /** * Constructor. * - * @param AttributeCollectionFactory $attributeCollectionFactory Product attribute collection factory. - * @param StoreManagerInterface $storeManager Store manager. - * @param IndexOperationInterface $indexManager Search engine index manager. - * @param MappingHelper $mappingHelper Mapping helper. - * @param RequestFieldMapper $requestFieldMapper Search request field mapper. - * @param string $indexName Search engine index name. - * @param string $typeName Search engine type name. + * @param AttributeCollectionFactory $attributeCollectionFactory Product attribute collection factory. + * @param StoreManagerInterface $storeManager Store manager. + * @param IndexOperationInterface $indexManager Search engine index manager. + * @param MappingHelper $mappingHelper Mapping helper. + * @param RequestFieldMapper $requestFieldMapper Search request field mapper. + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered navigation attributes provider. + * @param string $indexName Search engine index name. + * @param string $typeName Search engine type name. */ public function __construct( AttributeCollectionFactory $attributeCollectionFactory, @@ -92,16 +99,18 @@ public function __construct( IndexOperationInterface $indexManager, MappingHelper $mappingHelper, RequestFieldMapper $requestFieldMapper, + LayeredNavAttributesProvider $layeredNavAttributesProvider, $indexName = 'catalog_product', $typeName = 'product' ) { - $this->attributeCollectionFactory = $attributeCollectionFactory; - $this->storeManager = $storeManager; - $this->indexManager = $indexManager; - $this->mappingHelper = $mappingHelper; - $this->requestFieldMapper = $requestFieldMapper; - $this->indexName = $indexName; - $this->typeName = $typeName; + $this->attributeCollectionFactory = $attributeCollectionFactory; + $this->storeManager = $storeManager; + $this->indexManager = $indexManager; + $this->mappingHelper = $mappingHelper; + $this->requestFieldMapper = $requestFieldMapper; + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; + $this->indexName = $indexName; + $this->typeName = $typeName; } /** @@ -129,6 +138,13 @@ public function getAttributeCollection() $this->attributeCollection->addFieldToFilter('attribute_code', $fieldNames) ->addFieldToFilter('backend_type', ['neq' => 'datetime']); + + if (!empty($this->layeredNavAttributesProvider->getList())) { + $this->attributeCollection->addFieldToFilter( + 'attribute_code', + ['nin' => array_keys($this->layeredNavAttributesProvider->getList())] + ); + } } return $this->attributeCollection; diff --git a/src/module-elasticsuite-catalog/Api/LayeredNavAttributeInterface.php b/src/module-elasticsuite-catalog/Api/LayeredNavAttributeInterface.php new file mode 100644 index 000000000..3ddacb78b --- /dev/null +++ b/src/module-elasticsuite-catalog/Api/LayeredNavAttributeInterface.php @@ -0,0 +1,53 @@ + + * @copyright 2021 Smile + * @license Open Software License ("OSL") v. 3.0 + */ + +namespace Smile\ElasticsuiteCatalog\Api; + +/** + * LayeredNavAttributeInterface class. + * + * @category Smile + * @package Smile\ElasticsuiteCatalog + * @author Botis + */ +interface LayeredNavAttributeInterface +{ + /** + * Get attribute code. + * + * @return string + */ + public function getAttributeCode(): string; + + /** + * Get ES filter field. + * + * @return string + */ + public function getFilterField(): string; + + /** + * Get additional aggregation data. + * + * @return array + */ + public function getAdditionalAggregationData(): array; + + /** + * Skip attribute. + * + * @return bool + */ + public function skipAttribute(): bool; +} diff --git a/src/module-elasticsuite-catalog/Model/Attribute/LayeredNavAttributesProvider.php b/src/module-elasticsuite-catalog/Model/Attribute/LayeredNavAttributesProvider.php new file mode 100644 index 000000000..a418c04ee --- /dev/null +++ b/src/module-elasticsuite-catalog/Model/Attribute/LayeredNavAttributesProvider.php @@ -0,0 +1,100 @@ + + * @copyright 2021 Smile + * @license Open Software License ("OSL") v. 3.0 + */ +namespace Smile\ElasticsuiteCatalog\Model\Attribute; + +use Smile\ElasticsuiteCatalog\Api\LayeredNavAttributeInterface; + +/** + * Layered navigation attributes provider. + * + * @category Smile + * @package Smile\ElasticsuiteCatalog + * @author Botis + */ +class LayeredNavAttributesProvider +{ + /** + * @var LayeredNavAttributeInterface[] + */ + protected $attributes = []; + + /** + * LayeredNavAttributesProvider constructor. + * + * @param LayeredNavAttributeInterface[] $attributes Attributes. + */ + public function __construct($attributes = []) + { + $this->attributes = $attributes; + } + + /** + * Get Layered navigation attributes list. + * + * @return LayeredNavAttributeInterface[] + */ + public function getList(): array + { + $attributes = []; + foreach ($this->attributes as $attribute) { + if (!$attribute->skipAttribute()) { + $attributes[$attribute->getAttributeCode()] = $attribute; + } + } + + return $attributes; + } + + /** + * Get layered navigation attribute. + * + * @param string $attributeCode Attribute code. + * + * @return LayeredNavAttributeInterface|null + */ + public function getLayeredNavAttribute(string $attributeCode): ?LayeredNavAttributeInterface + { + return $this->getList()[$attributeCode] ?? null; + } + + /** + * Get layered navigation attribute by filter field. + * + * @param string $filterField Filter field. + * + * @return string|null + */ + public function getLayeredNavAttributeByFilterField(string $filterField): ?string + { + foreach ($this->getList() as $attribute) { + if ($attribute->getFilterField() === $filterField) { + return $attribute->getAttributeCode(); + } + } + + return null; + } + + /** + * Check if it is a layered navigation attribute. + * + * @param string $attributeCode Attribute code. + * + * @return bool + */ + public function isLayeredNavAttribute(string $attributeCode): bool + { + return isset($this->getList()[$attributeCode]); + } +} diff --git a/src/module-elasticsuite-catalog/Model/Layer/Filter/Boolean.php b/src/module-elasticsuite-catalog/Model/Layer/Filter/Boolean.php index f117483e1..beeb87e6f 100644 --- a/src/module-elasticsuite-catalog/Model/Layer/Filter/Boolean.php +++ b/src/module-elasticsuite-catalog/Model/Layer/Filter/Boolean.php @@ -13,6 +13,16 @@ */ namespace Smile\ElasticsuiteCatalog\Model\Layer\Filter; +use Magento\Catalog\Model\Layer; +use Magento\Catalog\Model\Layer\Filter\Item\DataBuilder; +use Magento\Catalog\Model\Layer\Filter\ItemFactory; +use Magento\Framework\Escaper; +use Magento\Framework\Filter\StripTags; +use Magento\Store\Model\StoreManagerInterface; +use Smile\ElasticsuiteCatalog\Api\LayeredNavAttributeInterface; +use Smile\ElasticsuiteCatalog\Helper\ProductAttribute; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; + /** * Product boolean filter implementation. * @@ -22,35 +32,80 @@ */ class Boolean extends Attribute { + /** + * @var LayeredNavAttributesProvider + */ + protected $layeredNavAttributesProvider; + + /** + * Boolean Constructor. + * + * @param ItemFactory $filterItemFactory Factory for item of the facets. + * @param StoreManagerInterface $storeManager Store manager. + * @param Layer $layer Catalog product layer. + * @param DataBuilder $itemDataBuilder Item data builder. + * @param StripTags $tagFilter String HTML tags filter. + * @param Escaper $escaper Html Escaper. + * @param ProductAttribute $mappingHelper Mapping helper. + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered navigation attributes Provider. + * @param array $data Custom data. + */ + public function __construct( + ItemFactory $filterItemFactory, + StoreManagerInterface $storeManager, + Layer $layer, + DataBuilder $itemDataBuilder, + StripTags $tagFilter, + Escaper $escaper, + ProductAttribute $mappingHelper, + LayeredNavAttributesProvider $layeredNavAttributesProvider, + array $data = [] + ) { + parent::__construct( + $filterItemFactory, + $storeManager, + $layer, + $itemDataBuilder, + $tagFilter, + $escaper, + $mappingHelper, + $data + ); + + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; + } + /** * {@inheritDoc} */ public function apply(\Magento\Framework\App\RequestInterface $request) { - $attributeValue = (bool) $request->getParam($this->_requestVar); + $attributeValue = $request->getParam($this->_requestVar); - if (!empty($attributeValue)) { + if ($attributeValue !== null) { if (!is_array($attributeValue)) { $attributeValue = [$attributeValue]; } - $this->currentFilterValue = $attributeValue; + $attributeValue = array_map(function ($value) { + return (bool) $value; + }, $attributeValue); + /** @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $productCollection */ $productCollection = $this->getLayer()->getProductCollection(); $productCollection->addFieldToFilter($this->getFilterField(), $attributeValue); $layerState = $this->getLayer()->getState(); - $booleanFilterLabels = []; foreach ($this->currentFilterValue as $currentFilter) { - $booleanFilterLabels[] = (string) $this->getAttributeModel()->getSource()->getOptionText((int) $currentFilter); + $filter = $this->_createItem( + $this->getAttributeModel()->getSource()->getOptionText((int) $currentFilter), + $this->currentFilterValue + ); + $filter->setRawValue($currentFilter); + $layerState->addFilter($filter); } - $filterLabel = implode(', ', $booleanFilterLabels); - - $filter = $this->_createItem($filterLabel, $this->currentFilterValue); - - $layerState->addFilter($filter); } return $this; @@ -69,7 +124,14 @@ public function hasMoreItems() */ protected function getFilterField() { - return $this->getAttributeModel()->getAttributeCode(); + $field = $this->getAttributeModel()->getAttributeCode(); + + $layeredNavAttribute = $this->layeredNavAttributesProvider->getLayeredNavAttribute($field); + if ($layeredNavAttribute instanceof LayeredNavAttributeInterface) { + $field = $layeredNavAttribute->getFilterField(); + } + + return $field; } /** @@ -85,7 +147,9 @@ protected function _initItems() foreach ($this->_items as $item) { $applyValue = $item->getLabel(); - if ($item->getValue() == \Magento\Eav\Model\Entity\Attribute\Source\Boolean::VALUE_YES) { + if ($item->getValue() == \Magento\Eav\Model\Entity\Attribute\Source\Boolean::VALUE_YES + || $item->getValue() == \Magento\Eav\Model\Entity\Attribute\Source\Boolean::VALUE_NO + ) { if (is_numeric($item->getLabel())) { $label = $this->getAttributeModel()->getSource()->getOptionText((int) $item->getLabel()); $item->setLabel((string) $label); diff --git a/src/module-elasticsuite-catalog/Model/Layer/Filter/Item/Attribute.php b/src/module-elasticsuite-catalog/Model/Layer/Filter/Item/Attribute.php index 26feb74a1..4926732c0 100644 --- a/src/module-elasticsuite-catalog/Model/Layer/Filter/Item/Attribute.php +++ b/src/module-elasticsuite-catalog/Model/Layer/Filter/Item/Attribute.php @@ -47,7 +47,7 @@ public function getRemoveUrl() $query = [$this->getFilter()->getRequestVar() => $this->getFilter()->getResetValue()]; if (is_array($this->getApplyValue())) { - $resetValue = array_diff($this->getApplyValue(), [$this->getLabel()]); + $resetValue = array_diff($this->getApplyValue(), [$this->getRawValue() ?? $this->getLabel()]); if (count($resetValue) < 2) { $resetValue = current($resetValue); } diff --git a/src/module-elasticsuite-catalog/Plugin/Search/Request/Product/Attribute/Aggregation/LayeredNavAttribute.php b/src/module-elasticsuite-catalog/Plugin/Search/Request/Product/Attribute/Aggregation/LayeredNavAttribute.php new file mode 100644 index 000000000..3bdb97a23 --- /dev/null +++ b/src/module-elasticsuite-catalog/Plugin/Search/Request/Product/Attribute/Aggregation/LayeredNavAttribute.php @@ -0,0 +1,68 @@ + + * @copyright 2021 Smile + * @license Open Software License ("OSL") v. 3.0 + */ +namespace Smile\ElasticsuiteCAtalog\Plugin\Search\Request\Product\Attribute\Aggregation; + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Smile\ElasticsuiteCatalog\Api\LayeredNavAttributeInterface; +use Smile\ElasticsuiteCatalog\Search\Request\Product\Attribute\AggregationInterface; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; + +/** + * Class LayeredNavAttribute. + * + * @category Smile + * @package Smile\ElasticsuiteCatalog + * @author Botis + */ +class LayeredNavAttribute +{ + /** + * @var LayeredNavAttributesProvider + */ + private $layeredNavAttributesProvider; + + /** + * LayeredNavAttribute Constructor. + * + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered navigation Attributes Provider. + */ + public function __construct( + LayeredNavAttributesProvider $layeredNavAttributesProvider + ) { + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; + } + + /** + * Replace filter field value for layered navigation attributes. + * + * @param AggregationInterface $subject Plugin subject. + * @param array $result Result. + * @param Attribute $attribute Attribute. + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * + * @return array + */ + public function afterGetAggregationData(AggregationInterface $subject, array $result, Attribute $attribute): array + { + $layeredNavAttribute = $this->layeredNavAttributesProvider->getLayeredNavAttribute( + $attribute->getAttributeCode() + ); + if ($layeredNavAttribute instanceof LayeredNavAttributeInterface) { + $result['name'] = $layeredNavAttribute->getFilterField(); + $result = array_merge($result, $layeredNavAttribute->getAdditionalAggregationData()); + } + + return $result; + } +} diff --git a/src/module-elasticsuite-catalog/Plugin/Search/RequestMapperPlugin.php b/src/module-elasticsuite-catalog/Plugin/Search/RequestMapperPlugin.php index 4f1daa6dc..44ff1f174 100644 --- a/src/module-elasticsuite-catalog/Plugin/Search/RequestMapperPlugin.php +++ b/src/module-elasticsuite-catalog/Plugin/Search/RequestMapperPlugin.php @@ -14,6 +14,8 @@ namespace Smile\ElasticsuiteCatalog\Plugin\Search; use Magento\Framework\Api\Search\SearchCriteriaInterface; +use Smile\ElasticsuiteCatalog\Api\LayeredNavAttributeInterface; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; use Smile\ElasticsuiteCatalog\Model\Search\Request\Field\Mapper as RequestFieldMapper; use Smile\ElasticsuiteCore\Api\Search\Request\ContainerConfigurationInterface; use Smile\ElasticsuiteCore\Model\Search\RequestMapper; @@ -22,6 +24,8 @@ /** * Apply catalog product settings to the search API request mapper. * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * * @category Smile * @package Smile\ElasticsuiteCatalog * @author Aurelien FOUCRET @@ -66,15 +70,21 @@ class RequestMapperPlugin */ private $requestFieldMapper; + /** + * @var LayeredNavAttributesProvider + */ + protected $layeredNavAttributesProvider; + /** * Constructor. * - * @param \Magento\Customer\Model\Session $customerSession Customer session. - * @param \Magento\Store\Model\StoreManagerInterface $storeManager Store manager. - * @param \Smile\ElasticsuiteCore\Helper\Mapping $mappingHelper Mapping helper. - * @param \Smile\ElasticsuiteCore\Api\Search\ContextInterface $searchContext Search context. - * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository Category Repository. - * @param RequestFieldMapper $requestFieldMapper Search request field mapper. + * @param \Magento\Customer\Model\Session $customerSession Customer session. + * @param \Magento\Store\Model\StoreManagerInterface $storeManager Store manager. + * @param \Smile\ElasticsuiteCore\Helper\Mapping $mappingHelper Mapping helper. + * @param \Smile\ElasticsuiteCore\Api\Search\ContextInterface $searchContext Search context. + * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository Category Repository. + * @param RequestFieldMapper $requestFieldMapper Search request field mapper. + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered navigation Attributes Provider. */ public function __construct( \Magento\Customer\Model\Session $customerSession, @@ -82,14 +92,16 @@ public function __construct( \Smile\ElasticsuiteCore\Helper\Mapping $mappingHelper, \Smile\ElasticsuiteCore\Api\Search\ContextInterface $searchContext, \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository, - RequestFieldMapper $requestFieldMapper + RequestFieldMapper $requestFieldMapper, + LayeredNavAttributesProvider $layeredNavAttributesProvider ) { - $this->customerSession = $customerSession; - $this->storeManager = $storeManager; - $this->mappingHelper = $mappingHelper; - $this->searchContext = $searchContext; - $this->categoryRepository = $categoryRepository; - $this->requestFieldMapper = $requestFieldMapper; + $this->customerSession = $customerSession; + $this->storeManager = $storeManager; + $this->mappingHelper = $mappingHelper; + $this->searchContext = $searchContext; + $this->categoryRepository = $categoryRepository; + $this->requestFieldMapper = $requestFieldMapper; + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; } /** @@ -154,7 +166,7 @@ public function afterGetFilters( foreach ($result as $fieldName => $filterValue) { $fieldName = $this->getMappingField($containerConfiguration, $fieldName); - $filters[$fieldName] = $filterValue; + $filters[$fieldName] = $this->getFieldValue($containerConfiguration, $fieldName, $filterValue); } $result = $filters; @@ -210,10 +222,23 @@ private function getMappingField(ContainerConfigurationInterface $containerConfi { $fieldName = $this->requestFieldMapper->getMappedFieldName($fieldName); + $layeredNavAttribute = $this->layeredNavAttributesProvider->getLayeredNavAttribute($fieldName); + if ($layeredNavAttribute instanceof LayeredNavAttributeInterface) { + return $layeredNavAttribute->getFilterField(); + } + try { - $optionTextFieldName = $this->mappingHelper->getOptionTextFieldName($fieldName); - $containerConfiguration->getMapping()->getField($optionTextFieldName); - $fieldName = $optionTextFieldName; + $field = $containerConfiguration->getMapping()->getField($fieldName); + } catch (\Exception $e) { + $field = null; + } + + try { + if ($field === null || $field->getType() != 'boolean') { + $optionTextFieldName = $this->mappingHelper->getOptionTextFieldName($fieldName); + $containerConfiguration->getMapping()->getField($optionTextFieldName); + $fieldName = $optionTextFieldName; + } } catch (\Exception $e) { ; } @@ -221,6 +246,31 @@ private function getMappingField(ContainerConfigurationInterface $containerConfi return $fieldName; } + /** + * Get field value in the proper type. + * + * @param ContainerConfigurationInterface $containerConfiguration Container configuration. + * @param string $fieldName Field name. + * @param mixed $fieldValue Field value. + * + * @return mixed + */ + private function getFieldValue(ContainerConfigurationInterface $containerConfiguration, string $fieldName, $fieldValue) + { + try { + $field = $containerConfiguration->getMapping()->getField($fieldName); + if ($field->getType() === 'boolean' && is_array($fieldValue)) { + foreach ($fieldValue as &$value) { + $value = (bool) $value; + } + } + } catch (\Exception $e) { + ; + } + + return $fieldValue; + } + /** * Return current category id for the search request. * diff --git a/src/module-elasticsuite-catalog/Search/Request/Product/Aggregation/Provider/FilterableAttributes/Modifier/Coverage.php b/src/module-elasticsuite-catalog/Search/Request/Product/Aggregation/Provider/FilterableAttributes/Modifier/Coverage.php index c025dfadd..c86ca5a93 100644 --- a/src/module-elasticsuite-catalog/Search/Request/Product/Aggregation/Provider/FilterableAttributes/Modifier/Coverage.php +++ b/src/module-elasticsuite-catalog/Search/Request/Product/Aggregation/Provider/FilterableAttributes/Modifier/Coverage.php @@ -14,8 +14,10 @@ namespace Smile\ElasticsuiteCatalog\Search\Request\Product\Aggregation\Provider\FilterableAttributes\Modifier; use Smile\ElasticsuiteCatalog\Model\Attribute\Source\FilterDisplayMode; +use Smile\ElasticsuiteCatalog\Model\Attribute\LayeredNavAttributesProvider; use Smile\ElasticsuiteCatalog\Search\Request\Product\Aggregation\Provider\FilterableAttributes\ModifierInterface; use Smile\ElasticsuiteCatalog\Search\Request\Product\Coverage\ProviderFactory as CoverageProviderFactory; +use Smile\ElasticsuiteCore\Search\Request\Builder as SearchRequestBuilder; /** * Coverage Modifier for filterable attributes provider. @@ -36,18 +38,26 @@ class Coverage implements ModifierInterface */ private $coverageProviderFactory; + /** + * @var LayeredNavAttributesProvider + */ + protected $layeredNavAttributesProvider; + /** * Coverage constructor. * - * @param \Smile\ElasticsuiteCore\Search\Request\Builder $coverageRequestBuilder Coverage Request builder. - * @param \Smile\ElasticsuiteCatalog\Search\Request\Product\Coverage\ProviderFactory $coverageProviderFactory Coverage provider factory. + * @param SearchRequestBuilder $coverageRequestBuilder Coverage Request builder. + * @param CoverageProviderFactory $coverageProviderFactory Coverage provider factory. + * @param LayeredNavAttributesProvider $layeredNavAttributesProvider Layered navigation attributes provider. */ public function __construct( - \Smile\ElasticsuiteCore\Search\Request\Builder $coverageRequestBuilder, - CoverageProviderFactory $coverageProviderFactory + SearchRequestBuilder $coverageRequestBuilder, + CoverageProviderFactory $coverageProviderFactory, + LayeredNavAttributesProvider $layeredNavAttributesProvider ) { - $this->coverageRequestBuilder = $coverageRequestBuilder; - $this->coverageProviderFactory = $coverageProviderFactory; + $this->coverageRequestBuilder = $coverageRequestBuilder; + $this->coverageProviderFactory = $coverageProviderFactory; + $this->layeredNavAttributesProvider = $layeredNavAttributesProvider; } /** @@ -68,7 +78,11 @@ public function modifyAttributes($storeId, $requestName, $attributes, $query, $f $attributeCode = $attribute->getAttributeCode(); $minCoverageRate = $attribute->getFacetMinCoverageRate(); - $isRelevant = isset($coverageRates[$attributeCode]) && ($coverageRates[$attributeCode] >= $minCoverageRate); + $isRelevant = true; + if (!$this->layeredNavAttributesProvider->isLayeredNavAttribute($attributeCode)) { + $isRelevant = isset($coverageRates[$attributeCode]) && ($coverageRates[$attributeCode] >= $minCoverageRate); + } + $forceDisplay = $attribute->getFacetDisplayMode() == FilterDisplayMode::ALWAYS_DISPLAYED; $isHidden = $attribute->getFacetDisplayMode() == FilterDisplayMode::ALWAYS_HIDDEN; diff --git a/src/module-elasticsuite-catalog/etc/frontend/di.xml b/src/module-elasticsuite-catalog/etc/frontend/di.xml index bc24af3f6..df846266f 100644 --- a/src/module-elasticsuite-catalog/etc/frontend/di.xml +++ b/src/module-elasticsuite-catalog/etc/frontend/di.xml @@ -101,14 +101,14 @@ searchFilterList - + categoryFilterList searchFilterList - - + + @@ -120,13 +120,13 @@ - + catalog_product_autocomplete - + Smile\ElasticsuiteCatalog\Model\Autocomplete\Product\Collection @@ -183,7 +183,7 @@ - + Smile\ElasticsuiteCatalog\Helper\ProductAttribute @@ -231,4 +231,9 @@ + + + +