Skip to content

Commit 950f0a5

Browse files
committed
Merge branch '2.10.x' into 2.11.x
2 parents a540544 + c7a4ffb commit 950f0a5

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Smile ElasticSuite to newer versions in the future.
6+
*
7+
* @category Smile
8+
* @package Smile\ElasticsuiteCatalog
9+
* @author Richard BAYET <richard.bayet@smile.fr>
10+
* @copyright 2025 Smile
11+
* @license Open Software License ("OSL") v. 3.0
12+
*/
13+
14+
namespace Smile\ElasticsuiteCatalog\Api\Product\Collection;
15+
16+
use Magento\Customer\Model\Group as CustomerGroup;
17+
use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection;
18+
19+
/**
20+
* Provide the parameters to build an aggregation collecting price statistics for a given collection.
21+
* Used in the collection's overridden _prepareStatisticsData method.
22+
* Create your own implementation if your price logic differs from Elasticsuite/Magento native behavior.
23+
*
24+
* @category Smile
25+
* @package Smile\ElasticsuiteCatalog
26+
*/
27+
interface PriceStatsAggregationProviderInterface
28+
{
29+
/**
30+
* Return an array of params to create an aggregation named $aggregationName
31+
* which is able to collect product price statistics
32+
* - count
33+
* - min price
34+
* - max price
35+
* - standard deviation
36+
*
37+
* @param Collection $collection The collection to get the price statistics aggregation for.
38+
* @param string $aggregationName The expected aggregation name.
39+
* @param int|null $customerGroupId The current customer group, if defined.
40+
*
41+
* @return array
42+
*/
43+
public function getAggregationData(
44+
Collection $collection,
45+
string $aggregationName,
46+
?int $customerGroupId = CustomerGroup::NOT_LOGGED_IN_ID
47+
): array;
48+
}

src/module-elasticsuite-catalog/Model/ResourceModel/Product/Fulltext/Collection.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
*/
1414
namespace Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext;
1515

16+
use Magento\Customer\Model\Group as CustomerGroup;
17+
use Magento\Framework\App\ObjectManager;
18+
use Smile\ElasticsuiteCatalog\Api\Product\Collection\PriceStatsAggregationProviderInterface;
1619
use Smile\ElasticsuiteCatalog\Model\Search\Request\Field\Mapper as RequestFieldMapper;
1720
use Smile\ElasticsuiteCore\Search\Adapter\Elasticsuite\Response\QueryResponse;
1821
use Smile\ElasticsuiteCore\Search\Request\BucketInterface;
22+
use Smile\ElasticsuiteCore\Search\Request\MetricInterface;
1923
use Smile\ElasticsuiteCore\Search\Request\QueryInterface;
2024
use Smile\ElasticsuiteCore\Search\RequestInterface;
2125

@@ -101,6 +105,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
101105
*/
102106
private $requestFieldMapper;
103107

108+
/**
109+
* @var PriceStatsAggregationProviderInterface
110+
*/
111+
private $priceStatsAggProvider;
112+
104113
/**
105114
* Constructor.
106115
*
@@ -184,6 +193,7 @@ public function __construct(
184193
$this->searchEngine = $searchEngine;
185194
$this->requestFieldMapper = $requestFieldMapper;
186195
$this->searchRequestName = $searchRequestName;
196+
$this->priceStatsAggProvider = ObjectManager::getInstance()->get(PriceStatsAggregationProviderInterface::class);
187197
}
188198

189199
/**
@@ -612,6 +622,58 @@ protected function _afterLoad()
612622
return parent::_afterLoad();
613623
}
614624

625+
/**
626+
* @SuppressWarnings(PHPMD.CamelCaseMethodName)
627+
*
628+
* Prepares min and max price using Elasticsearch metric aggregation.
629+
* Ensures compatibility with Magento Core's getMinPrice()/getMaxPrice().
630+
*
631+
* @return self
632+
*/
633+
protected function _prepareStatisticsData()
634+
{
635+
$storeId = $this->getStoreId();
636+
$requestName = $this->searchRequestName;
637+
$customerGroupId = (int) ($this->_productLimitationFilters['customer_group_id'] ?? CustomerGroup::NOT_LOGGED_IN_ID);
638+
$aggregationName = 'collection_price_stats';
639+
640+
$priceStatsAgg = $this->priceStatsAggProvider->getAggregationData(
641+
$this,
642+
$aggregationName,
643+
$customerGroupId
644+
);
645+
646+
$searchRequest = $this->requestBuilder->create(
647+
$storeId,
648+
$requestName,
649+
0,
650+
0,
651+
$this->query,
652+
[],
653+
$this->filters,
654+
$this->queryFilters,
655+
[$priceStatsAgg],
656+
);
657+
658+
$response = $this->searchEngine->search($searchRequest);
659+
$aggregations = $response->getAggregations();
660+
661+
$metrics = [];
662+
$bucket = $aggregations->getBucket($aggregationName);
663+
if (null !== $bucket) {
664+
$metrics = current($bucket->getValues())->getMetrics();
665+
}
666+
667+
$rate = $this->getCurrencyRate();
668+
669+
$this->_pricesCount = (int) ($metrics['count'] ?? 0);
670+
$this->_minPrice = round(((float) ($metrics['min'] ?? 0)) * $rate, 2);
671+
$this->_maxPrice = round(((float) ($metrics['max'] ?? 0)) * $rate, 2);
672+
$this->_priceStandardDeviation = round(((float) ($metrics['std_deviation'] ?? 0)) * $rate, 2);
673+
674+
return $this;
675+
}
676+
615677
/**
616678
* Load product count :
617679
* - collection size
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Smile ElasticSuite to newer versions in the future.
6+
*
7+
* @category Smile
8+
* @package Smile\ElasticsuiteCatalog
9+
* @author Richard BAYET <richard.bayet@smile.fr>
10+
* @copyright 2025 Smile
11+
* @license Open Software License ("OSL") v. 3.0
12+
*/
13+
namespace Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection;
14+
15+
use Magento\Customer\Model\Group as CustomerGroup;
16+
use Smile\ElasticsuiteCatalog\Api\Product\Collection\PriceStatsAggregationProviderInterface;
17+
use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection;
18+
use Smile\ElasticsuiteCore\Search\Request\BucketInterface;
19+
use Smile\ElasticsuiteCore\Search\Request\MetricInterface;
20+
21+
/**
22+
* Default product collection price statistics aggregation provider.
23+
*
24+
* @category Smile
25+
* @package Smile\ElasticsuiteCatalog
26+
*/
27+
class PriceStatsAggregationProvider implements PriceStatsAggregationProviderInterface
28+
{
29+
/**
30+
* {@inheritDoc}
31+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
32+
*/
33+
public function getAggregationData(
34+
Collection $collection,
35+
string $aggregationName,
36+
?int $customerGroupId = CustomerGroup::NOT_LOGGED_IN_ID
37+
): array {
38+
return [
39+
'name' => $aggregationName,
40+
'type' => BucketInterface::TYPE_METRIC,
41+
'field' => 'price.price',
42+
'metricType' => MetricInterface::TYPE_STATS,
43+
'nestedFilter' => ['price.customer_group_id' => $customerGroupId],
44+
];
45+
}
46+
}

src/module-elasticsuite-catalog/etc/di.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,4 +455,8 @@
455455
<type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
456456
<plugin name="injectSortDirectionPerCategory" type="\Smile\ElasticsuiteCatalog\Plugin\Category\Toolbar\SortDirectionPerCategoryPlugin"/>
457457
</type>
458+
459+
<!-- Aggregation provider for the product collection's _prepareStatisticsData method -->
460+
<preference for="Smile\ElasticsuiteCatalog\Api\Product\Collection\PriceStatsAggregationProviderInterface"
461+
type="Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection\PriceStatsAggregationProvider" />
458462
</config>

0 commit comments

Comments
 (0)