Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.9.x] Allow search request field mapping to be configured + layered navigation attributes #2272

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -41,6 +42,11 @@ class Attribute implements LayerBuilderInterface
*/
private $attributeRepository;

/**
* @var LayeredNavAttributesProvider
*/
protected $layeredNavAttributesProvider;

/**
* @var array
*/
Expand All @@ -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;
}

/**
Expand All @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions src/module-elasticsuite-catalog-graph-ql/etc/graphql/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,9 @@
</argument>
</arguments>
</type>

<type name="Smile\ElasticsuiteCatalog\Search\Request\Product\Attribute\AggregationInterface">
<plugin name="layered_nav_attributes_replace_filter_field"
type="Smile\ElasticsuiteCatalog\Plugin\Search\Request\Product\Attribute\Aggregation\LayeredNavAttribute"/>
</type>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
*/
namespace Smile\ElasticsuiteCatalogRule\Model\Rule\Condition\Product;

use Magento\Store\Model\StoreManagerInterface;
use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory;
use Magento\Store\Model\StoreManagerInterface;
use Smile\ElasticsuiteCatalog\Model\Search\Request\Field\Mapper as RequestFieldMapper;
use Smile\ElasticsuiteCore\Api\Index\IndexOperationInterface;
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.
Expand Down Expand Up @@ -70,37 +72,45 @@ class AttributeList
private $mappingHelper;

/**
* @var @array
* @var RequestFieldMapper
*/
private $fieldNameMapping = [
'price' => 'price.price',
'category_ids' => 'category.category_id',
];
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 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,
StoreManagerInterface $storeManager,
IndexOperationInterface $indexManager,
MappingHelper $mappingHelper,
RequestFieldMapper $requestFieldMapper,
LayeredNavAttributesProvider $layeredNavAttributesProvider,
$indexName = 'catalog_product',
$typeName = 'product'
) {
$this->attributeCollectionFactory = $attributeCollectionFactory;
$this->storeManager = $storeManager;
$this->indexManager = $indexManager;
$this->indexName = $indexName;
$this->typeName = $typeName;
$this->mappingHelper = $mappingHelper;
$this->attributeCollectionFactory = $attributeCollectionFactory;
$this->storeManager = $storeManager;
$this->indexManager = $indexManager;
$this->mappingHelper = $mappingHelper;
$this->requestFieldMapper = $requestFieldMapper;
$this->layeredNavAttributesProvider = $layeredNavAttributesProvider;
$this->indexName = $indexName;
$this->typeName = $typeName;
}

/**
Expand All @@ -112,13 +122,13 @@ public function getAttributeCollection()
{
if ($this->attributeCollection === null) {
$this->attributeCollection = $this->attributeCollectionFactory->create();
$attributeNameMapping = array_flip($this->fieldNameMapping);
$attributeNameMapping = $this->requestFieldMapper->getFieldNameMappings();

$arrayNameCb = function (FieldInterface $field) use ($attributeNameMapping) {
$attributeName = $field->getName();

if (isset($attributeNameMapping[$attributeName])) {
$attributeName = $attributeNameMapping[$attributeName];
if ($fieldMapping = array_search($attributeName, $attributeNameMapping)) {
$attributeName = $fieldMapping;
}

return $attributeName;
Expand All @@ -128,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;
Expand All @@ -142,9 +159,7 @@ public function getAttributeCollection()
*/
public function getField($attributeName)
{
if (isset($this->fieldNameMapping[$attributeName])) {
$attributeName = $this->fieldNameMapping[$attributeName];
}
$attributeName = $this->requestFieldMapper->getMappedFieldName($attributeName);

return $this->getMapping()->getField($attributeName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Smile ElasticSuite to newer
* versions in the future.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Botis <botis@smile.fr>
* @copyright 2021 Smile
* @license Open Software License ("OSL") v. 3.0
*/

namespace Smile\ElasticsuiteCatalog\Api;

/**
* LayeredNavAttributeInterface class.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Botis <botis@smile.fr>
*/
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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Smile ElasticSuite to newer
* versions in the future.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Botis <botis@smile.fr>
* @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 <botis@smile.fr>
*/
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]);
}
}
Loading