src/module-elasticsuite-core/Search/Adapter/Elasticsuite/Request/Aggregation/Builder.php
<?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\ElasticsuiteCore
* @author Aurelien FOUCRET <aurelien.foucret@smile.fr>
* @copyright 2020 Smile
* @license Open Software License ("OSL") v. 3.0
*/
namespace Smile\ElasticsuiteCore\Search\Adapter\Elasticsuite\Request\Aggregation;
use Smile\ElasticsuiteCore\Search\Adapter\Elasticsuite\Request\Query\Builder as QueryBuilder;
use Smile\ElasticsuiteCore\Search\Request\BucketInterface;
/**
*
* @category Smile
* @package Smile\ElasticsuiteCore
* @author Aurelien FOUCRET <aurelien.foucret@smile.fr>
*/
class Builder
{
/**
* @var QueryBuilder
*/
private $queryBuilder;
/**
* @var BuilderInterface[]
*/
private $builders;
/**
* @var PipelineBuilderInterface[]
*/
private $pipelineBuilders;
/**
* Constructor.
*
* @param QueryBuilder $queryBuilder Query builder used to build
* Queries inside sort orders.
* @param BuilderInterface[] $builders Aggregation builder implementations
* @param PipelineBuilderInterface[] $pipelineBuilders Pipeline aggregation builder implementations
*/
public function __construct(
QueryBuilder $queryBuilder,
array $builders = [],
array $pipelineBuilders = []
) {
$this->queryBuilder = $queryBuilder;
$this->builders = $builders;
$this->pipelineBuilders = $pipelineBuilders;
}
/**
* Build ES aggregations from search request buckets.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @param BucketInterface[] $buckets Bucket to be converted into ES aggregations
*
* @return array
*/
public function buildAggregations(array $buckets = [])
{
$aggregations = [];
foreach ($buckets as $bucket) {
$bucketType = $bucket->getType();
$builder = $this->getBuilder($bucketType);
$aggregation = $builder->buildBucket($bucket);
$subAggregations = $aggregation['aggregations'] ?? [];
if (!empty($bucket->getChildBuckets())) {
$subAggregations = array_merge($subAggregations, $this->buildAggregations($bucket->getChildBuckets()));
}
foreach ($bucket->getMetrics() as $metric) {
$metricDefinition = array_merge(['field' => $metric->getField()], $metric->getConfig() ?? []);
if (isset($metricDefinition['script'])) {
unset($metricDefinition['field']);
}
$subAggregations[$metric->getName()] = [$metric->getType() => $metricDefinition];
}
foreach ($bucket->getPipelines() as $pipeline) {
$pipelineType = $pipeline->getType();
$pipelineBuilder = $this->getPipelineBuilder($pipelineType);
$pipelineAgg = $pipelineBuilder->buildPipeline($pipeline);
$subAggregations[$pipeline->getName()] = $pipelineAgg;
}
if (!empty($subAggregations)) {
$aggregation['aggregations'] = $subAggregations;
}
if ($bucket->isNested()) {
if ($bucket->getNestedFilter()) {
$aggregation = [
'filter' => $this->queryBuilder->buildQuery($bucket->getNestedFilter()),
'aggregations' => [$bucket->getName() => $aggregation],
];
}
$aggregation = [
'nested' => ['path' => $bucket->getNestedPath()],
'aggregations' => [$bucket->getName() => $aggregation],
];
}
if ($bucket->getFilter()) {
$aggregation = [
'filter' => $this->queryBuilder->buildQuery($bucket->getFilter()),
'aggregations' => [$bucket->getName() => $aggregation],
];
}
$aggregations[$bucket->getName()] = $aggregation;
}
return $aggregations;
}
/**
* Retrieve the builder used to convert a bucket into ES aggregation.
*
* @param string $bucketType Bucket type to be built.
*
* @return BuilderInterface
*/
private function getBuilder($bucketType)
{
if (!isset($this->builders[$bucketType])) {
throw new \InvalidArgumentException("No builder found for aggregation type {$bucketType}.");
}
return $this->builders[$bucketType];
}
/**
* Retrieve the builder used to convert a pipeline into an ES aggregation.
*
* @param string $pipelineType Pipeline type to be built.
*
* @return PipelineBuilderInterface
*/
private function getPipelineBuilder($pipelineType)
{
if (!isset($this->pipelineBuilders[$pipelineType])) {
throw new \InvalidArgumentException("No builder found for pipeline aggregation type {$pipelineType}.");
}
return $this->pipelineBuilders[$pipelineType];
}
}