diff --git a/Adapter/Aggregation/Builder.php b/Adapter/Aggregation/Builder.php
new file mode 100644
index 0000000..cbbf223
--- /dev/null
+++ b/Adapter/Aggregation/Builder.php
@@ -0,0 +1,168 @@
+dataProviderContainer = array_map(
+ function (DataProviderInterface $dataProvider) {
+ return $dataProvider;
+ },
+ $dataProviderContainer
+ );
+ $this->aggregationContainer = array_map(
+ function (BucketBuilderInterface $bucketBuilder) {
+ return $bucketBuilder;
+ },
+ $aggregationContainer
+ );
+ $this->dataProviderFactory = $dataProviderFactory
+ ?: ObjectManager::getInstance()->get(DataProviderFactory::class);
+
+ $this->productFactory = $productFactory;
+ }
+
+ public function build(RequestInterface $request, array $queryResult)
+ {
+ $aggregations = [];
+ $buckets = $request->getAggregation();
+
+ $facets = $this->getFacets();
+
+ $dataProvider = $this->dataProviderFactory->create(
+ $this->dataProviderContainer[$request->getIndex()],
+ $this->query
+ );
+
+ foreach ($buckets as $bucket) {
+ if (count($facets) && isset($facets[$bucket->getField()])) {
+ $aggregations[$bucket->getName()] =
+ $this->formatAggregation($bucket->getField(), $facets[$bucket->getField()]);
+ } else {
+ $bucketAggregationBuilder = $this->aggregationContainer[$bucket->getType()];
+ $aggregations[$bucket->getName()] = $bucketAggregationBuilder->build(
+ $bucket,
+ $request->getDimensions(),
+ $queryResult,
+ $dataProvider
+ );
+ }
+ }
+
+ $this->query = null;
+
+ return $aggregations;
+ }
+
+
+ private function formatAggregation($attribute, $facetData)
+ {
+ $aggregation = [];
+
+ foreach ($facetData as $value => $count) {
+ $optionId = $this->getOptionIdByLabel($attribute, $value);
+ $aggregation[$optionId] = [
+ 'value' => (string) $optionId,
+ 'count' => (string) $count,
+ ];
+ }
+
+ return $aggregation;
+ }
+
+ private function getOptionIdByLabel($attributeCode, $optionLabel)
+ {
+ $product = $this->getProduct();
+ $isAttributeExist = $product->getResource()->getAttribute($attributeCode);
+ $optionId = '';
+ if ($isAttributeExist && $isAttributeExist->usesSource()) {
+ $optionId = $isAttributeExist->getSource()->getOptionId($optionLabel);
+ }
+
+ return $optionId;
+ }
+
+ /**
+ * @return \Magento\Catalog\Model\Product
+ */
+ private function getProduct()
+ {
+ if (!$this->product) {
+ $this->product = $this->productFactory->create();
+ }
+
+ return $this->product;
+ }
+
+ /**
+ * Sets the QueryContainer instance to the internal property in order to use it in build process
+ *
+ * @param QueryContainer $query
+ * @return \Magento\Elasticsearch\SearchAdapter\Aggregation\Builder
+ */
+ public function setQuery(QueryContainer $query)
+ {
+ $this->query = $query;
+
+ return $this;
+ }
+
+ public function setFacets($facets)
+ {
+ $this->facets = $facets;
+ }
+
+ private function getFacets()
+ {
+ return $this->facets;
+ }
+
+}
diff --git a/Adapter/AlgoliaElasticSearch5Adapter.php b/Adapter/AlgoliaElasticSearch5Adapter.php
index bed46b6..6d7d24f 100755
--- a/Adapter/AlgoliaElasticSearch5Adapter.php
+++ b/Adapter/AlgoliaElasticSearch5Adapter.php
@@ -3,9 +3,10 @@
namespace Algolia\AlgoliaSearchElastic\Adapter;
use Algolia\AlgoliaSearch\Helper\AdapterHelper;
+use Algolia\AlgoliaSearchElastic\Helper\ElasticAdapterHelper;
use Magento\Elasticsearch\Elasticsearch5\SearchAdapter\Adapter as ElasticSearch5Adapter;
use Magento\Elasticsearch\Elasticsearch5\SearchAdapter\Mapper;
-use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as AggregationBuilder;
+use Algolia\AlgoliaSearchElastic\Adapter\Aggregation\Builder as AggregationBuilder;
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
use Magento\Elasticsearch\SearchAdapter\ResponseFactory;
use Magento\Elasticsearch\SearchAdapter\QueryContainerFactory;
@@ -14,10 +15,12 @@
class AlgoliaElasticSearch5Adapter extends ElasticSearch5Adapter
{
-
/** @var AdapterHelper */
private $adapterHelper;
+ /** @var ElasticAdapterHelper */
+ private $esAdapterHelper;
+
/** @var QueryContainerFactory */
private $queryContainerFactory;
@@ -30,6 +33,7 @@ class AlgoliaElasticSearch5Adapter extends ElasticSearch5Adapter
* @param QueryContainerFactory $queryContainerFactory
* @param LoggerInterface|null $logger
* @param AdapterHelper $adapterHelper
+ * @param ElasticAdapterHelper $esAdapterHelper
*/
public function __construct(
ConnectionManager $connectionManager,
@@ -38,13 +42,15 @@ public function __construct(
AggregationBuilder $aggregationBuilder,
QueryContainerFactory $queryContainerFactory,
LoggerInterface $logger = null,
- AdapterHelper $adapterHelper
+ AdapterHelper $adapterHelper,
+ ElasticAdapterHelper $esAdapterHelper
) {
parent::__construct($connectionManager, $mapper, $responseFactory, $aggregationBuilder, $queryContainerFactory,
$logger);
$this->adapterHelper = $adapterHelper;
+ $this->esAdapterHelper = $esAdapterHelper;
$this->queryContainerFactory = $queryContainerFactory;
}
@@ -55,19 +61,13 @@ public function __construct(
*/
public function query(RequestInterface $request)
{
- if (!$this->adapterHelper->isAllowed()
- || !(
- $this->adapterHelper->isSearch() ||
- $this->adapterHelper->isReplaceCategory() ||
- $this->adapterHelper->isReplaceAdvancedSearch() ||
- $this->adapterHelper->isLandingPage()
- )
- ) {
+ if (!$this->esAdapterHelper->replaceElasticSearchResults()) {
return parent::query($request);
}
$aggregationBuilder = $this->aggregationBuilder;
$query = $this->mapper->buildQuery($request);
+
$aggregationBuilder->setQuery($this->queryContainerFactory->create(['query' => $query]));
$rawResponse = [];
@@ -77,7 +77,7 @@ public function query(RequestInterface $request)
try {
// If instant search is on, do not make a search query unless SEO request is set to 'Yes'
if (!$this->adapterHelper->isInstantEnabled() || $this->adapterHelper->makeSeoRequest()) {
- list($rawResponse, $totalHits) = $this->adapterHelper->getDocumentsFromAlgolia($request);
+ list($rawResponse, $totalHits, $facets) = $this->adapterHelper->getDocumentsFromAlgolia();
$rawResponse = $this->transformResponseForElastic($rawResponse);
}
@@ -85,7 +85,9 @@ public function query(RequestInterface $request)
return parent::query($request);
}
+ $aggregationBuilder->setFacets($facets);
$aggregations = $aggregationBuilder->build($request, $rawResponse);
+
$response = [
'documents' => $rawResponse,
'aggregations' => $aggregations,
@@ -105,9 +107,10 @@ private function transformResponseForElastic(array $rawResponse)
foreach ($rawResponse as &$hit) {
$hit['_id'] = $hit['entity_id'];
}
- $rawResponse['hits'] = ['hits' => $rawResponse];
}
+ $rawResponse['hits'] = ['hits' => $rawResponse];
+
return $rawResponse;
}
}
diff --git a/Adapter/AlgoliaElasticSearchAdapter.php b/Adapter/AlgoliaElasticSearchAdapter.php
index d331a05..2da3b48 100755
--- a/Adapter/AlgoliaElasticSearchAdapter.php
+++ b/Adapter/AlgoliaElasticSearchAdapter.php
@@ -3,8 +3,9 @@
namespace Algolia\AlgoliaSearchElastic\Adapter;
use Algolia\AlgoliaSearch\Helper\AdapterHelper;
+use Algolia\AlgoliaSearchElastic\Helper\ElasticAdapterHelper;
use Magento\Elasticsearch\SearchAdapter\Adapter as ElasticSearchAdapter;
-use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as AggregationBuilder;
+use Algolia\AlgoliaSearchElastic\Adapter\Aggregation\Builder as AggregationBuilder;
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
use Magento\Elasticsearch\SearchAdapter\Mapper;
use Magento\Elasticsearch\SearchAdapter\ResponseFactory;
@@ -17,17 +18,21 @@ class AlgoliaElasticSearchAdapter extends ElasticSearchAdapter
/** @var AdapterHelper */
private $adapterHelper;
+ /** @var ElasticAdapterHelper */
+ private $esAdapterHelper;
+
/** @var QueryContainerFactory */
private $queryContainerFactory;
/**
- * AlgoliaElasticSearch5Adapter constructor.
+ * AlgoliaElasticSearchAdapter constructor.
* @param ConnectionManager $connectionManager
* @param Mapper $mapper
* @param ResponseFactory $responseFactory
* @param AggregationBuilder $aggregationBuilder
* @param QueryContainerFactory $queryContainerFactory
* @param AdapterHelper $adapterHelper
+ * @param ElasticAdapterHelper $esAdapterHelper
*/
public function __construct(
ConnectionManager $connectionManager,
@@ -35,12 +40,14 @@ public function __construct(
ResponseFactory $responseFactory,
AggregationBuilder $aggregationBuilder,
QueryContainerFactory $queryContainerFactory,
- AdapterHelper $adapterHelper
+ AdapterHelper $adapterHelper,
+ ElasticAdapterHelper $esAdapterHelper
) {
parent::__construct($connectionManager, $mapper, $responseFactory, $aggregationBuilder, $queryContainerFactory);
$this->adapterHelper = $adapterHelper;
+ $this->esAdapterHelper = $esAdapterHelper;
}
/**
@@ -49,14 +56,7 @@ public function __construct(
*/
public function query(RequestInterface $request)
{
- if (!$this->adapterHelper->isAllowed()
- || !(
- $this->adapterHelper->isSearch() ||
- $this->adapterHelper->isReplaceCategory() ||
- $this->adapterHelper->isReplaceAdvancedSearch() ||
- $this->adapterHelper->isLandingPage()
- )
- ) {
+ if (!$this->esAdapterHelper->replaceElasticSearchResults()) {
return parent::query($request);
}
@@ -71,7 +71,7 @@ public function query(RequestInterface $request)
try {
// If instant search is on, do not make a search query unless SEO request is set to 'Yes'
if (!$this->adapterHelper->isInstantEnabled() || $this->adapterHelper->makeSeoRequest()) {
- list($rawResponse, $totalHits) = $this->adapterHelper->getDocumentsFromAlgolia($request);
+ list($rawResponse, $totalHits, $facets) = $this->adapterHelper->getDocumentsFromAlgolia();
$rawResponse = $this->transformResponseForElastic($rawResponse);
}
@@ -79,7 +79,9 @@ public function query(RequestInterface $request)
return parent::query($request);
}
+ $aggregationBuilder->setFacets($facets);
$aggregations = $aggregationBuilder->build($request, $rawResponse);
+
$response = [
'documents' => $rawResponse,
'aggregations' => $aggregations,
@@ -99,9 +101,10 @@ private function transformResponseForElastic(array $rawResponse)
foreach ($rawResponse as &$hit) {
$hit['_id'] = $hit['entity_id'];
}
- $rawResponse['hits'] = ['hits' => $rawResponse];
}
+ $rawResponse['hits'] = ['hits' => $rawResponse];
+
return $rawResponse;
}
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..dd5ad76
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,7 @@
+# CHANGE LOG
+
+## 0.0.1
+
+### UPDATES
+- Updated composer.json (#4) (by @vmalyk)
+- Fix Bad Request Warning and Builder Aggregation (#6)
\ No newline at end of file
diff --git a/Helper/ElasticAdapterHelper.php b/Helper/ElasticAdapterHelper.php
new file mode 100644
index 0000000..56d6d11
--- /dev/null
+++ b/Helper/ElasticAdapterHelper.php
@@ -0,0 +1,64 @@
+adapterHelper = $adapterHelper;
+ $this->configHelper = $configHelper;
+ }
+
+ /**
+ * @return bool
+ */
+ public function replaceElasticSearchResults()
+ {
+ if (!$this->adapterHelper->isAllowed()
+ || !(
+ $this->adapterHelper->isSearch() ||
+ $this->adapterHelper->isReplaceCategory() ||
+ $this->adapterHelper->isReplaceAdvancedSearch() ||
+ $this->adapterHelper->isLandingPage()
+ )
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function getStoreId()
+ {
+ return $this->configHelper->getStoreId();
+ }
+
+ public function getFacets()
+ {
+ return $this->configHelper->getFacets($this->getStoreId());
+ }
+
+}
diff --git a/Plugin/FulltextCollection.php b/Plugin/FulltextCollection.php
new file mode 100644
index 0000000..ec44326
--- /dev/null
+++ b/Plugin/FulltextCollection.php
@@ -0,0 +1,108 @@
+adapterHelper = $adapterHelper;
+ $this->esAdapterHelper = $esAdapterHelper;
+ $this->productFactory = $productFactory;
+ }
+
+ /**
+ * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject
+ * @param $field
+ * @param null $condition
+ */
+ public function beforeAddFieldToFilter(
+ \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject,
+ $field,
+ $condition = null
+ ) {
+ if (!$condition || !$this->esAdapterHelper->replaceElasticSearchResults()) {
+ return [$field, $condition];
+ }
+
+ if (is_array($this->getFacets()) && in_array($field, $this->getFacets())) {
+ $condition = $this->getOptionIdByLabel($field, $condition);
+ }
+
+ return [$field, $condition];
+ }
+
+ /**
+ * @param string $attributeCode
+ * @param null $optionLabel
+ * @return string
+ */
+ private function getOptionIdByLabel($attributeCode, $optionLabel = null)
+ {
+ if ($optionLabel && !is_array($optionLabel)) {
+ $product = $this->getProduct();
+ $isAttributeExist = $product->getResource()->getAttribute($attributeCode);
+ if ($isAttributeExist && $isAttributeExist->usesSource()) {
+ $optionLabel = $isAttributeExist->getSource()->getOptionId($optionLabel);
+ }
+ }
+
+ return $optionLabel;
+ }
+
+ /**
+ * @return \Magento\Catalog\Model\Product
+ */
+ public function getProduct()
+ {
+ if (!$this->product) {
+ $this->product = $this->productFactory->create();
+ }
+
+ return $this->product;
+ }
+
+ /**
+ * @return array
+ */
+ public function getFacets()
+ {
+ if (!$this->facets) {
+ $facets = [];
+ $configFacets = $this->esAdapterHelper->getFacets();
+ if (is_array($configFacets) && count($configFacets)) {
+ $facets = array_map(function ($facet) {
+ return $facet['attribute'];
+ }, $configFacets);
+ }
+ $this->facets = $facets;
+ }
+
+ return $this->facets;
+ }
+
+}
diff --git a/composer.json b/composer.json
index ac87e7d..b4ff4ad 100644
--- a/composer.json
+++ b/composer.json
@@ -3,11 +3,9 @@
"description": "Algolia Search ES Compatibility module for Magento >=2.3.1|>=2.2.8 and Algolia Search >=1.12 extension",
"type": "magento2-module",
"license": ["MIT"],
- "version": "0.0.0",
+ "version": "0.0.1",
"require": {
- "php": "~7.1.3||~7.2.0",
- "algolia/algoliasearch-client-php": ">=1.27.0 <2.0",
- "algolia/algoliasearch-magento-2": ">=1.8.0",
+ "algolia/algoliasearch-magento-2": ">=1.12.0",
"magento/module-elasticsearch": ">=100.2.7"
},
"autoload": {
diff --git a/etc/di.xml b/etc/di.xml
index de86527..81a3e28 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -4,4 +4,8 @@
+
+
+
+
diff --git a/etc/module.xml b/etc/module.xml
index 24c1a2d..5042df8 100644
--- a/etc/module.xml
+++ b/etc/module.xml
@@ -1,6 +1,6 @@
-
+