Skip to content

Commit

Permalink
Release 0.0.1 (#8)
Browse files Browse the repository at this point in the history
### UPDATES

- Updated composer.json (#4) (by @vmalyk)
- Fix Bad Request Warning and Builder Aggregation (#6)
bsuravech authored Jan 8, 2020
1 parent b5f28dc commit 072a34b
Showing 9 changed files with 386 additions and 31 deletions.
168 changes: 168 additions & 0 deletions Adapter/Aggregation/Builder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php

namespace Algolia\AlgoliaSearchElastic\Adapter\Aggregation;

use Algolia\AlgoliaSearch\Model\Indexer\Product;
use Algolia\AlgoliaSearchElastic\Helper\ElasticAdapterHelper;
use Magento\Catalog\Model\ProductFactory;
use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as ElasticSearchBuilder;
use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder\BucketBuilderInterface;
use Magento\Elasticsearch\SearchAdapter\Aggregation\DataProviderFactory;
use Magento\Elasticsearch\SearchAdapter\QueryContainer;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Search\Dynamic\DataProviderInterface;
use Magento\Framework\Search\RequestInterface;

class Builder extends ElasticSearchBuilder
{
/**
* @var DataProviderFactory
*/
private $dataProviderFactory;

/**
* @var QueryContainer
*/
private $query = null;

/**
* @var ProductFactory
*/
private $productFactory;

/**
* @var \Magento\Catalog\Model\Product
*/
private $product;

/**
* @var array
*/
private $facets = [];

/**
* @param array $dataProviderContainer
* @param array $aggregationContainer
* @param DataProviderFactory|null $dataProviderFactory
* @param ProductFactory $productFactory
*/
public function __construct(
array $dataProviderContainer,
array $aggregationContainer,
DataProviderFactory $dataProviderFactory = null,
ProductFactory $productFactory
) {
$this->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;
}

}
29 changes: 16 additions & 13 deletions Adapter/AlgoliaElasticSearch5Adapter.php
Original file line number Diff line number Diff line change
@@ -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,15 +77,17 @@ 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);
}

} catch (AlgoliaConnectionException $e) {
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;
}
}
29 changes: 16 additions & 13 deletions Adapter/AlgoliaElasticSearchAdapter.php
Original file line number Diff line number Diff line change
@@ -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,30 +18,36 @@ 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,
Mapper $mapper,
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,15 +71,17 @@ 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);
}

} catch (AlgoliaConnectionException $e) {
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;
}
}
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# CHANGE LOG

## 0.0.1

### UPDATES
- Updated composer.json (#4) (by @vmalyk)
- Fix Bad Request Warning and Builder Aggregation (#6)
64 changes: 64 additions & 0 deletions Helper/ElasticAdapterHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Algolia\AlgoliaSearchElastic\Helper;

use Algolia\AlgoliaSearch\Helper\Adapter\FiltersHelper;
use Algolia\AlgoliaSearch\Helper\AdapterHelper;
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
use Algolia\AlgoliaSearch\Helper\Data as AlgoliaDataHelper;
use Magento\CatalogSearch\Helper\Data as CatalogSearchDataHelper;

class ElasticAdapterHelper
{
/**
* @var AdapterHelper
*/
private $adapterHelper;

/**
* @var ConfigHelper
*/
private $configHelper;

/**
* @param AdapterHelper $adapterHelper
* @param ConfigHelper $configHelper
*/
public function __construct(
AdapterHelper $adapterHelper,
ConfigHelper $configHelper
) {
$this->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());
}

}
108 changes: 108 additions & 0 deletions Plugin/FulltextCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace Algolia\AlgoliaSearchElastic\Plugin;

use Algolia\AlgoliaSearch\Helper\AdapterHelper;
use Algolia\AlgoliaSearchElastic\Helper\ElasticAdapterHelper;
use Magento\Catalog\Model\ProductFactory;

class FulltextCollection
{
/** @var AdapterHelper */
private $adapterHelper;

/** @var ElasticAdapterHelper */
private $esAdapterHelper;

/** @var ProductFactory */
private $productFactory;

/** @var \Magento\Catalog\Model\Product */
private $product;

private $facets;

/**
* @param AdapterHelper $adapterHelper
*/
public function __construct(
AdapterHelper $adapterHelper,
ElasticAdapterHelper $esAdapterHelper,
ProductFactory $productFactory
) {
$this->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;
}

}
6 changes: 2 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -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": {
4 changes: 4 additions & 0 deletions etc/di.xml
Original file line number Diff line number Diff line change
@@ -4,4 +4,8 @@
<preference for="Magento\Elasticsearch\SearchAdapter\Adapter" type="Algolia\AlgoliaSearchElastic\Adapter\AlgoliaElasticSearchAdapter"/>
<preference for="Magento\Elasticsearch\Elasticsearch5\SearchAdapter\Adapter" type="Algolia\AlgoliaSearchElastic\Adapter\AlgoliaElasticSearch5Adapter"/>

<type name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection">
<plugin name="algoliasearchelastic_search_filter" type="Algolia\AlgoliaSearchElastic\Plugin\FulltextCollection" />
</type>

</config>
2 changes: 1 addition & 1 deletion etc/module.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Algolia_AlgoliaSearchElastic" setup_version="0.0.0">
<module name="Algolia_AlgoliaSearchElastic" setup_version="0.0.1">
<sequence>
<module name="Magento_Elasticsearch"/>
<module name="Algolia_AlgoliaSearch"/>

0 comments on commit 072a34b

Please sign in to comment.