Skip to content

Commit

Permalink
#ESP-252 Add special attributes management
Browse files Browse the repository at this point in the history
 * Add special attributes management
 * Add No value filter for boolean
 * Fix applying boolean filters on GraphQL
  • Loading branch information
botisSmile committed Oct 6, 2021
1 parent b0ed615 commit c644177
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 45 deletions.
53 changes: 53 additions & 0 deletions src/module-elasticsuite-catalog/Api/SpecialAttributeInterface.php
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;

/**
* SpecialAttributeInterface class.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Botis <botis@smile.fr>
*/
interface SpecialAttributeInterface
{
/**
* 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
Expand Up @@ -18,6 +18,7 @@
use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilderInterface;
use Magento\Framework\Api\Search\AggregationInterface;
use Magento\Framework\Api\Search\BucketInterface;
use Smile\ElasticsuiteCatalog\Model\Attribute\SpecialAttributesProvider;
use Smile\ElasticsuiteCore\Helper\Mapping;

/**
Expand Down Expand Up @@ -52,6 +53,11 @@ class Attribute // Not implementing the LayerBuilderInterface because it did not
*/
private $attributeRepository;

/**
* @var SpecialAttributesProvider
*/
protected $specialAttributesProvider;

/**
* @var array
*/
Expand All @@ -61,19 +67,22 @@ class Attribute // Not implementing the LayerBuilderInterface because it did not
];

/**
* @param \Magento\Framework\ObjectManagerInterface $objectManager Object Manager
* @param AttributeRepository $attributeRepository Attribute Repository
* @param array $bucketNameFilter Bucket Filter
* @param \Magento\Framework\ObjectManagerInterface $objectManager Object Manager.
* @param AttributeRepository $attributeRepository Attribute Repository.
* @param SpecialAttributesProvider $specialAttributesProvider Special Attributes Provider.
* @param array $bucketNameFilter Bucket Filter.
*/
public function __construct(
\Magento\Framework\ObjectManagerInterface $objectManager,
AttributeRepository $attributeRepository,
SpecialAttributesProvider $specialAttributesProvider,
$bucketNameFilter = []
) {
// Using Object Manager for BC with Magento <2.3.4.
$this->layerFormatter = $objectManager->get(LayerFormatter::class);
$this->bucketNameFilter = \array_merge($this->bucketNameFilter, $bucketNameFilter);
$this->attributeRepository = $attributeRepository;
$this->specialAttributesProvider = $specialAttributesProvider;
}

/**
Expand All @@ -92,6 +101,7 @@ public function build(AggregationInterface $aggregation, ?int $storeId): array
if (substr($bucketName, 0, strlen($prefix)) === $prefix) {
$attributeCode = substr($bucketName, strlen($prefix));
}
$attributeCode = $this->specialAttributesProvider->getSpecialAttributeByFilterField($bucketName) ?? $attributeCode;

$label = $attributeCode;
try {
Expand Down
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\SpecialAttributeInterface;

/**
* Special Attributes Provider.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Botis <botis@smile.fr>
*/
class SpecialAttributesProvider
{
/**
* @var SpecialAttributeInterface[]
*/
protected $attributes = [];

/**
* SpecialAttributesProvider constructor.
*
* @param SpecialAttributeInterface[] $attributes Attributes.
*/
public function __construct($attributes = [])
{
$this->attributes = $attributes;
}

/**
* Get special attributes list.
*
* @return SpecialAttributeInterface[]
*/
public function getList(): array
{
$attributes = [];
foreach ($this->attributes as $attribute) {
if (!$attribute->skipAttribute()) {
$attributes[$attribute->getAttributeCode()] = $attribute;
}
}

return $attributes;
}

/**
* Get special attribute.
*
* @param string $attributeCode Attribute code.
*
* @return SpecialAttributeInterface|null
*/
public function getSpecialAttribute(string $attributeCode): ?SpecialAttributeInterface
{
return $this->getList()[$attributeCode] ?? null;
}

/**
* Get special attribute.
*
* @param string $filterField Filter field.
*
* @return string|null
*/
public function getSpecialAttributeByFilterField(string $filterField): ?string
{
foreach ($this->getList() as $attribute) {
if ($attribute->getFilterField() === $filterField) {
return $attribute->getAttributeCode();
}
}

return null;
}

/**
* Check if attribute is special.
*
* @param string $attributeCode Attribute code.
*
* @return bool
*/
public function isSpecialAttribute(string $attributeCode): bool
{
return isset($this->getList()[$attributeCode]);
}
}
88 changes: 76 additions & 12 deletions src/module-elasticsuite-catalog/Model/Layer/Filter/Boolean.php
Original file line number Diff line number Diff line change
Expand Up @@ -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\SpecialAttributeInterface;
use Smile\ElasticsuiteCatalog\Helper\ProductAttribute;
use Smile\ElasticsuiteCatalog\Model\Attribute\SpecialAttributesProvider;

/**
* Product boolean filter implementation.
*
Expand All @@ -22,35 +32,80 @@
*/
class Boolean extends Attribute
{
/**
* @var SpecialAttributesProvider
*/
protected $specialAttributesProvider;

/**
* 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 SpecialAttributesProvider $specialAttributesProvider Special Attributes Provider.
* @param array $data Custom data.
*/
public function __construct(
ItemFactory $filterItemFactory,
StoreManagerInterface $storeManager,
Layer $layer,
DataBuilder $itemDataBuilder,
StripTags $tagFilter,
Escaper $escaper,
ProductAttribute $mappingHelper,
SpecialAttributesProvider $specialAttributesProvider,
array $data = []
) {
parent::__construct(
$filterItemFactory,
$storeManager,
$layer,
$itemDataBuilder,
$tagFilter,
$escaper,
$mappingHelper,
$data
);

$this->specialAttributesProvider = $specialAttributesProvider;
}

/**
* {@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;
Expand All @@ -69,7 +124,14 @@ public function hasMoreItems()
*/
protected function getFilterField()
{
return $this->getAttributeModel()->getAttributeCode();
$field = $this->getAttributeModel()->getAttributeCode();

$specialAttribute = $this->specialAttributesProvider->getSpecialAttribute($field);
if ($specialAttribute instanceof SpecialAttributeInterface) {
$field = $specialAttribute->getFilterField();
}

return $field;
}

/**
Expand All @@ -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);
Expand Down
Loading

0 comments on commit c644177

Please sign in to comment.