Skip to content

Commit 325da0c

Browse files
authored
Merge branch 'develop' into master
2 parents 19d2026 + 589a7a8 commit 325da0c

File tree

77 files changed

+3441
-444
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+3441
-444
lines changed

.circleci/config.yml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,19 @@ shared: &shared
3333
command: |
3434
mv ~/build_directory/algoliasearch-magento-2/dev/tests/install-config-mysql.php ~/magento_directory/dev/tests/integration/etc/install-config-mysql.php
3535
36+
- run:
37+
name: Before setup
38+
command: |
39+
wget https://alg.li/algolia-keys && chmod +x algolia-keys
40+
3641
- run:
3742
name: Run tests
3843
command: |
3944
cd ~/magento_directory/dev/tests/integration
45+
export CI_BUILD_NUM=$CIRCLE_BUILD_NUM
46+
export CI_PROJ_USERNAME=$CIRCLE_PROJECT_USERNAME
47+
export CI_PROJ_REPONAME=$CIRCLE_PROJECT_REPONAME
48+
eval $(~/build_directory/algoliasearch-magento-2/algolia-keys export)
4049
php -dmemory_limit=-1 ../../../vendor/bin/phpunit ../../../vendor/algolia/algoliasearch-magento-2/Test
4150
4251
jobs:
@@ -55,10 +64,33 @@ jobs:
5564
docker:
5665
- image: algolia/magento2-circleci:2.3.0
5766

67+
"phpcompatibility":
68+
docker: # run the steps with Docker with PHP 7.2
69+
- image: circleci/php:7.2
70+
steps:
71+
- checkout
72+
- run: sudo composer self-update
73+
- run: composer config http-basic.repo.magento.com ${MAGENTO_AUTH_USERNAME} ${MAGENTO_AUTH_PASSWORD}
74+
- restore_cache:
75+
keys:
76+
- composer-v1-{{ checksum "composer.lock" }}
77+
- composer-v1-
78+
- run: composer install -n --prefer-dist --ignore-platform-reqs --no-progress
79+
- save_cache:
80+
key: composer-v1-{{ checksum "composer.lock" }}
81+
paths:
82+
- vendor
83+
- run:
84+
name: PHPCS PHPCompatibility
85+
command: |
86+
./vendor/bin/phpcs --config-set installed_paths vendor/phpcompatibility/php-compatibility/PHPCompatibility/
87+
# vendor/ is large and seems to break phpcs, ls+grep+xargs hack is used to send folders to phpcs
88+
ls -d */ | grep -vE 'dev|Test|vendor' | xargs ./vendor/bin/phpcs -p --standard=PHPCompatibility --runtime-set testVersion 7.1- --runtime-set ignore_warnings_on_exit true
89+
5890
workflows:
5991
version: 2
6092
build:
6193
jobs:
62-
- "magento-2.1"
6394
- "magento-2.2"
6495
- "magento-2.3"
96+
- "phpcompatibility"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ dev/frontend/node_modules/
22
dev/bin/auth.json
33
composer.lock
44
vendor/
5+
.php_cs.cache

Adapter/Aggregation/Builder.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Adapter\Aggregation;
4+
5+
use Magento\Catalog\Model\ProductFactory;
6+
use Magento\Framework\App\ResourceConnection;
7+
use Magento\Framework\DB\Ddl\Table;
8+
use Magento\Framework\Search\Adapter\Aggregation\AggregationResolverInterface;
9+
use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Container as AggregationContainer;
10+
use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderContainer;
11+
use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage;
12+
use Magento\Framework\Search\RequestInterface;
13+
14+
class Builder
15+
{
16+
/** @var DataProviderContainer */
17+
private $dataProviderContainer;
18+
19+
/** @var AggregationContainer */
20+
private $aggregationContainer;
21+
22+
/** @var ResourceConnection */
23+
private $resource;
24+
25+
/** @var AggregationResolverInterface */
26+
private $aggregationResolver;
27+
28+
/** @var ProductFactory */
29+
private $productFactory;
30+
31+
/**
32+
* @param ResourceConnection $resource
33+
* @param DataProviderContainer $dataProviderContainer
34+
* @param AggregationContainer $aggregationContainer
35+
* @param AggregationResolverInterface $aggregationResolver
36+
* @param ProductFactory $productFactory
37+
*/
38+
public function __construct(
39+
ResourceConnection $resource,
40+
DataProviderContainer $dataProviderContainer,
41+
AggregationContainer $aggregationContainer,
42+
AggregationResolverInterface $aggregationResolver,
43+
ProductFactory $productFactory
44+
) {
45+
$this->dataProviderContainer = $dataProviderContainer;
46+
$this->aggregationContainer = $aggregationContainer;
47+
$this->resource = $resource;
48+
$this->aggregationResolver = $aggregationResolver;
49+
$this->productFactory = $productFactory;
50+
}
51+
52+
public function build(RequestInterface $request, Table $documentsTable, array $documents, array $facets)
53+
{
54+
return $this->processAggregations($request, $documentsTable, $documents, $facets);
55+
}
56+
57+
private function processAggregations(RequestInterface $request, Table $documentsTable, $documents, $facets)
58+
{
59+
$aggregations = [];
60+
$documentIds = $documents ? $this->extractDocumentIds($documents) : $this->getDocumentIds($documentsTable);
61+
$buckets = $this->aggregationResolver->resolve($request, $documentIds);
62+
$dataProvider = $this->dataProviderContainer->get($request->getIndex());
63+
64+
foreach ($buckets as $bucket) {
65+
if (isset($facets[$bucket->getField()])) {
66+
$aggregations[$bucket->getName()] =
67+
$this->formatAggregation($bucket->getField(), $facets[$bucket->getField()]);
68+
} else {
69+
$aggregationBuilder = $this->aggregationContainer->get($bucket->getType());
70+
$aggregations[$bucket->getName()] = $aggregationBuilder->build(
71+
$dataProvider,
72+
$request->getDimensions(),
73+
$bucket,
74+
$documentsTable
75+
);
76+
}
77+
}
78+
79+
return $aggregations;
80+
}
81+
82+
private function formatAggregation($attribute, $facetData)
83+
{
84+
$aggregation = [];
85+
86+
foreach ($facetData as $value => $count) {
87+
$optionId = $this->getOptionIdByLabel($attribute, $value);
88+
$aggregation[$optionId] = [
89+
'value' => (string) $optionId,
90+
'count' => (string) $count,
91+
];
92+
}
93+
94+
return $aggregation;
95+
}
96+
97+
private function getOptionIdByLabel($attributeCode, $optionLabel)
98+
{
99+
$product = $this->productFactory->create();
100+
$isAttributeExist = $product->getResource()->getAttribute($attributeCode);
101+
$optionId = '';
102+
if ($isAttributeExist && $isAttributeExist->usesSource()) {
103+
$optionId = $isAttributeExist->getSource()->getOptionId($optionLabel);
104+
}
105+
106+
return $optionId;
107+
}
108+
109+
private function extractDocumentIds(array $documents)
110+
{
111+
return $documents ? array_keys($documents) : [];
112+
}
113+
114+
private function getDocumentIds(Table $documentsTable)
115+
{
116+
$select = $this->getConnection()
117+
->select()
118+
->from($documentsTable->getName(), TemporaryStorage::FIELD_ENTITY_ID);
119+
120+
return $this->getConnection()->fetchCol($select);
121+
}
122+
123+
private function getConnection()
124+
{
125+
return $this->resource->getConnection();
126+
}
127+
}

Adapter/Algolia.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Algolia\AlgoliaSearch\Adapter;
44

5+
use Algolia\AlgoliaSearch\Adapter\Aggregation\Builder as AlgoliaAggregationBuilder;
56
use Algolia\AlgoliaSearch\Helper\AdapterHelper;
67
use AlgoliaSearch\AlgoliaConnectionException;
78
use Magento\Framework\App\ResourceConnection;
@@ -38,6 +39,9 @@ class Algolia implements AdapterInterface
3839
/** @var AdapterHelper */
3940
private $adapterHelper;
4041

42+
/** @var AlgoliaAggregationBuilder */
43+
private $algoliaAggregationBuilder;
44+
4145
/** @var DocumentFactory */
4246
private $documentFactory;
4347

@@ -53,6 +57,7 @@ class Algolia implements AdapterInterface
5357
* @param AggregationBuilder $aggregationBuilder
5458
* @param TemporaryStorageFactory $temporaryStorageFactory
5559
* @param AdapterHelper $adapterHelper
60+
* @param AlgoliaAggregationBuilder $algoliaAggregationBuilder
5661
* @param DocumentFactory $documentFactory
5762
*/
5863
public function __construct(
@@ -62,6 +67,7 @@ public function __construct(
6267
AggregationBuilder $aggregationBuilder,
6368
TemporaryStorageFactory $temporaryStorageFactory,
6469
AdapterHelper $adapterHelper,
70+
AlgoliaAggregationBuilder $algoliaAggregationBuilder,
6571
DocumentFactory $documentFactory
6672
) {
6773
$this->mapper = $mapper;
@@ -70,6 +76,7 @@ public function __construct(
7076
$this->aggregationBuilder = $aggregationBuilder;
7177
$this->temporaryStorageFactory = $temporaryStorageFactory;
7278
$this->adapterHelper = $adapterHelper;
79+
$this->algoliaAggregationBuilder = $algoliaAggregationBuilder;
7380
$this->documentFactory = $documentFactory;
7481
}
7582

@@ -93,11 +100,12 @@ public function query(RequestInterface $request)
93100
$documents = [];
94101
$totalHits = 0;
95102
$table = null;
103+
$facetsFromAlgolia = null;
96104

97105
try {
98106
// If instant search is on, do not make a search query unless SEO request is set to 'Yes'
99107
if (!$this->adapterHelper->isInstantEnabled() || $this->adapterHelper->makeSeoRequest()) {
100-
list($documents, $totalHits) = $this->adapterHelper->getDocumentsFromAlgolia();
108+
list($documents, $totalHits, $facetsFromAlgolia) = $this->adapterHelper->getDocumentsFromAlgolia();
101109
}
102110

103111
$apiDocuments = array_map([$this, 'getApiDocument'], $documents);
@@ -106,7 +114,8 @@ public function query(RequestInterface $request)
106114
return $this->nativeQuery($request);
107115
}
108116

109-
$aggregations = $this->aggregationBuilder->build($request, $table, $documents);
117+
$aggregations = $this->algoliaAggregationBuilder->build($request, $table, $documents, $facetsFromAlgolia);
118+
110119
$response = [
111120
'documents' => $documents,
112121
'aggregations' => $aggregations,
@@ -167,6 +176,7 @@ private function getConnection()
167176
* Get rows size
168177
*
169178
* @param Select $query
179+
*
170180
* @return int
171181
*/
172182
private function getSize(Select $query)
@@ -185,6 +195,7 @@ private function getSize(Select $query)
185195
* Reset limit and offset
186196
*
187197
* @param Select $query
198+
*
188199
* @return Select
189200
*/
190201
private function getSelectCountSql(Select $query)

Block/Navigation.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Block;
4+
5+
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
6+
7+
class Navigation extends \Magento\LayeredNavigation\Block\Navigation
8+
{
9+
/** @var ConfigHelper */
10+
private $configHelper;
11+
12+
/**
13+
* Navigation constructor.
14+
*
15+
* @param \Magento\Framework\View\Element\Template\Context $context
16+
* @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
17+
* @param \Magento\Catalog\Model\Layer\FilterList $filterList
18+
* @param \Magento\Catalog\Model\Layer\AvailabilityFlagInterface $visibilityFlag
19+
* @param ConfigHelper $configHelper
20+
* @param array $data
21+
*/
22+
public function __construct(
23+
\Magento\Framework\View\Element\Template\Context $context,
24+
\Magento\Catalog\Model\Layer\Resolver $layerResolver,
25+
\Magento\Catalog\Model\Layer\FilterList $filterList,
26+
\Magento\Catalog\Model\Layer\AvailabilityFlagInterface $visibilityFlag,
27+
ConfigHelper $configHelper,
28+
array $data
29+
) {
30+
parent::__construct($context, $layerResolver, $filterList, $visibilityFlag, $data);
31+
$this->configHelper = $configHelper;
32+
33+
if ($this->configHelper->isBackendRenderingEnabled()) {
34+
$this->getLayout()->unsetElement('catalog.compare.sidebar');
35+
$this->getLayout()->unsetElement('wishlist_sidebar');
36+
}
37+
}
38+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Block\Navigation\Renderer;
4+
5+
use Magento\Catalog\Model\Layer\Filter\FilterInterface;
6+
use Magento\Framework\View\Element\Template;
7+
use Magento\LayeredNavigation\Block\Navigation\FilterRendererInterface;
8+
9+
class CategoryRenderer extends Template implements FilterRendererInterface
10+
{
11+
/** @var string */
12+
protected $_template = 'Algolia_AlgoliaSearch::layer/filter/category.phtml';
13+
14+
public function isMultipleSelectEnabled()
15+
{
16+
return false;
17+
}
18+
19+
public function render(FilterInterface $filter)
20+
{
21+
$html = '';
22+
$this->filter = $filter;
23+
24+
if ($this->canRenderFilter()) {
25+
$this->assign('filterItems', $filter->getItems());
26+
$html = $this->_toHtml();
27+
$this->assign('filterItems', []);
28+
}
29+
30+
return $html;
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
protected function canRenderFilter()
37+
{
38+
return true;
39+
}
40+
}

0 commit comments

Comments
 (0)