Skip to content

Commit 6a07f36

Browse files
authored
EZP-27458: Impl. Aggregation API (#192)
1 parent 340c86a commit 6a07f36

File tree

91 files changed

+4404
-26
lines changed

Some content is hidden

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

91 files changed

+4404
-26
lines changed

bundle/ApiLoader/SolrEngineFactory.php

+10-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class SolrEngineFactory
4141
private $documentMapper;
4242

4343
/** @var \EzSystems\EzPlatformSolrSearchEngine\ResultExtractor */
44-
private $resultExtractor;
44+
private $contentResultExtractor;
45+
46+
/** @var \EzSystems\EzPlatformSolrSearchEngine\ResultExtractor */
47+
private $locationResultExtractor;
4548

4649
public function __construct(
4750
RepositoryConfigurationProvider $repositoryConfigurationProvider,
@@ -51,7 +54,8 @@ public function __construct(
5154
CoreFilterRegistry $coreFilterRegistry,
5255
Handler $contentHandler,
5356
DocumentMapper $documentMapper,
54-
ResultExtractor $resultExtractor
57+
ResultExtractor $contentResultExtractor,
58+
ResultExtractor $locationResultExtractor
5559
) {
5660
$this->repositoryConfigurationProvider = $repositoryConfigurationProvider;
5761
$this->defaultConnection = $defaultConnection;
@@ -60,7 +64,8 @@ public function __construct(
6064
$this->coreFilterRegistry = $coreFilterRegistry;
6165
$this->contentHandler = $contentHandler;
6266
$this->documentMapper = $documentMapper;
63-
$this->resultExtractor = $resultExtractor;
67+
$this->contentResultExtractor = $contentResultExtractor;
68+
$this->locationResultExtractor = $locationResultExtractor;
6469
}
6570

6671
public function buildEngine()
@@ -76,7 +81,8 @@ public function buildEngine()
7681
$gateway,
7782
$this->contentHandler,
7883
$this->documentMapper,
79-
$this->resultExtractor,
84+
$this->contentResultExtractor,
85+
$this->locationResultExtractor,
8086
$coreFilter
8187
);
8288
}

bundle/Resources/config/services.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ services:
1515
$coreFilterRegistry: '@EzSystems\EzPlatformSolrSearchEngine\CoreFilter\CoreFilterRegistry'
1616
$contentHandler: "@ezpublish.spi.persistence.content_handler"
1717
$documentMapper: "@ezpublish.search.solr.document_mapper"
18-
$resultExtractor: "@ezpublish.search.solr.result_extractor"
18+
$contentResultExtractor: "@ezpublish.search.solr.result_extractor.content"
19+
$locationResultExtractor: "@ezpublish.search.solr.result_extractor.location"
1920

2021
ezpublish.solr.boost_factor_provider_factory:
2122
class: "%ezpublish.solr.boost_factor_provider_factory.class%"

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
],
1313
"require": {
1414
"php": "^7.3",
15+
"ext-json": "*",
1516
"ezsystems/ezplatform-kernel": "^1.2@dev",
1617
"netgen/query-translator": "^1.0.2",
1718
"symfony/http-kernel": "^5.0",

lib/FieldMapper/ContentFieldMapper/BlockDocumentsBaseContentFields.php

+5
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ public function mapFields(Content $content)
142142
array_keys($versionInfo->names),
143143
new FieldType\MultipleStringField()
144144
),
145+
new Field(
146+
'content_language_codes_raw',
147+
array_keys($versionInfo->names),
148+
new FieldType\MultipleIdentifierField(['raw' => true])
149+
),
145150
new Field(
146151
'content_main_language_code',
147152
$contentInfo->mainLanguageCode,

lib/Gateway/Native.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function __construct(
102102
*/
103103
public function findContent(Query $query, array $languageSettings = [])
104104
{
105-
$parameters = $this->contentQueryConverter->convert($query);
105+
$parameters = $this->contentQueryConverter->convert($query, $languageSettings);
106106

107107
return $this->internalFind($parameters, $languageSettings);
108108
}

lib/Handler.php

+30-6
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,26 @@ class Handler implements SearchHandlerInterface, Capable, ContentTranslationHand
7474
/**
7575
* Result extractor.
7676
*
77+
* @deprecated since eZ Platform 3.2.0, to be removed in eZ Platform 4.0.0. Use $contentResultExtractor or $locationResultExtractor instead of $resultExtractor.
78+
*
7779
* @var \EzSystems\EzPlatformSolrSearchEngine\ResultExtractor
7880
*/
7981
protected $resultExtractor;
8082

83+
/**
84+
* Content result extractor.
85+
*
86+
* @var \EzSystems\EzPlatformSolrSearchEngine\ResultExtractor
87+
*/
88+
protected $contentResultExtractor;
89+
90+
/**
91+
* Location result extractor.
92+
*
93+
* @var \EzSystems\EzPlatformSolrSearchEngine\ResultExtractor
94+
*/
95+
protected $locationResultExtractor;
96+
8197
/**
8298
* Core filter service.
8399
*
@@ -97,14 +113,19 @@ public function __construct(
97113
Gateway $gateway,
98114
ContentHandler $contentHandler,
99115
DocumentMapper $mapper,
100-
ResultExtractor $resultExtractor,
116+
ResultExtractor $contentResultExtractor,
117+
ResultExtractor $locationResultExtractor,
101118
CoreFilter $coreFilter
102119
) {
103120
$this->gateway = $gateway;
104121
$this->contentHandler = $contentHandler;
105122
$this->mapper = $mapper;
106-
$this->resultExtractor = $resultExtractor;
123+
$this->contentResultExtractor = $contentResultExtractor;
124+
$this->locationResultExtractor = $locationResultExtractor;
107125
$this->coreFilter = $coreFilter;
126+
127+
// For BC these are still set
128+
$this->resultExtractor = $contentResultExtractor;
108129
}
109130

110131
/**
@@ -131,9 +152,11 @@ public function findContent(Query $query, array $languageFilter = [])
131152
DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_CONTENT
132153
);
133154

134-
return $this->resultExtractor->extract(
155+
return $this->contentResultExtractor->extract(
135156
$this->gateway->findContent($query, $languageFilter),
136-
$query->facetBuilders
157+
$query->facetBuilders,
158+
$query->aggregations,
159+
$languageFilter
137160
);
138161
}
139162

@@ -201,9 +224,10 @@ public function findLocations(LocationQuery $query, array $languageFilter = [])
201224
DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_LOCATION
202225
);
203226

204-
return $this->resultExtractor->extract(
227+
return $this->locationResultExtractor->extract(
205228
$this->gateway->findLocations($query, $languageFilter),
206-
$query->facetBuilders
229+
$query->facetBuilders,
230+
$query->aggregations
207231
);
208232
}
209233

lib/Query/AggregationVisitor.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
12+
13+
interface AggregationVisitor
14+
{
15+
/**
16+
* Check if visitor is applicable to current aggreagtion.
17+
*/
18+
public function canVisit(Aggregation $aggregation, array $languageFilter): bool;
19+
20+
/**
21+
* @return string[]
22+
*/
23+
public function visit(
24+
AggregationVisitor $dispatcherVisitor,
25+
Aggregation $aggregation,
26+
array $languageFilter
27+
): array;
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor;
10+
11+
use DateTimeInterface;
12+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractRangeAggregation;
13+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
14+
use EzSystems\EzPlatformSolrSearchEngine\Query\AggregationVisitor;
15+
16+
abstract class AbstractRangeAggregationVisitor implements AggregationVisitor
17+
{
18+
/**
19+
* @param \eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractRangeAggregation $aggregation
20+
*/
21+
public function visit(
22+
AggregationVisitor $dispatcherVisitor,
23+
Aggregation $aggregation,
24+
array $languageFilter
25+
): array {
26+
$field = $this->getTargetField($aggregation);
27+
28+
$rangeFacets = [];
29+
foreach ($aggregation->getRanges() as $range) {
30+
$from = $this->formatRangeValue($range->getFrom());
31+
$to = $this->formatRangeValue($range->getTo());
32+
33+
$rangeFacets["${from}_${to}"] = [
34+
'type' => 'query',
35+
'q' => sprintf('%s:[%s TO %s}', $field, $from, $to),
36+
];
37+
}
38+
39+
return [
40+
'type' => 'query',
41+
'q' => '*:*',
42+
'facet' => $rangeFacets,
43+
];
44+
}
45+
46+
abstract protected function getTargetField(AbstractRangeAggregation $aggregation): string;
47+
48+
private function formatRangeValue($value): string
49+
{
50+
if ($value === null) {
51+
return '*';
52+
}
53+
54+
if ($value instanceof DateTimeInterface) {
55+
return $value->format('Y-m-d\\TH:i:s\\Z');
56+
}
57+
58+
return (string)$value;
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractStatsAggregation;
12+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
13+
use EzSystems\EzPlatformSolrSearchEngine\Query\AggregationVisitor;
14+
15+
abstract class AbstractStatsAggregationVisitor implements AggregationVisitor
16+
{
17+
/**
18+
* @param \eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractStatsAggregation $aggregation
19+
*/
20+
public function visit(
21+
AggregationVisitor $dispatcherVisitor,
22+
Aggregation $aggregation,
23+
array $languageFilter
24+
): array {
25+
$field = $this->getTargetField($aggregation);
26+
27+
return [
28+
'type' => 'query',
29+
'q' => '*:*',
30+
'facet' => [
31+
'sum' => "sum($field)",
32+
'min' => "min($field)",
33+
'max' => "max($field)",
34+
'avg' => "avg($field)",
35+
],
36+
];
37+
}
38+
39+
abstract protected function getTargetField(AbstractStatsAggregation $aggregation): string;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractTermAggregation;
12+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
13+
use EzSystems\EzPlatformSolrSearchEngine\Query\AggregationVisitor;
14+
15+
abstract class AbstractTermAggregationVisitor implements AggregationVisitor
16+
{
17+
/**
18+
* @param \eZ\Publish\API\Repository\Values\Content\Query\Aggregation\AbstractTermAggregation $aggregation
19+
*/
20+
public function visit(
21+
AggregationVisitor $dispatcherVisitor,
22+
Aggregation $aggregation,
23+
array $languageFilter
24+
): array {
25+
return [
26+
'type' => 'terms',
27+
'field' => $this->getTargetField($aggregation),
28+
'limit' => $aggregation->getLimit(),
29+
'mincount' => $aggregation->getMinCount(),
30+
];
31+
}
32+
33+
abstract protected function getTargetField(AbstractTermAggregation $aggregation): string;
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
12+
13+
/**
14+
* Resolves search index field name used for aggregation.
15+
*/
16+
interface AggregationFieldResolver
17+
{
18+
public function resolveTargetField(Aggregation $aggregation): string;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor\AggregationFieldResolver;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation\FieldAggregation;
12+
use eZ\Publish\API\Repository\Values\Content\Query\Aggregation;
13+
use eZ\Publish\Core\Search\Common\FieldNameResolver;
14+
use EzSystems\EzPlatformSolrSearchEngine\Query\Common\AggregationVisitor\AggregationFieldResolver;
15+
use RuntimeException;
16+
17+
final class ContentFieldAggregationFieldResolver implements AggregationFieldResolver
18+
{
19+
/** @var \eZ\Publish\Core\Search\Common\FieldNameResolver */
20+
private $fieldNameResolver;
21+
22+
/** @var string */
23+
private $searchFieldName;
24+
25+
public function __construct(FieldNameResolver $fieldNameResolver, string $searchFieldName)
26+
{
27+
$this->fieldNameResolver = $fieldNameResolver;
28+
$this->searchFieldName = $searchFieldName;
29+
}
30+
31+
public function resolveTargetField(Aggregation $aggregation): string
32+
{
33+
if (!($aggregation instanceof FieldAggregation)) {
34+
throw new RuntimeException('Expected instance of ' . FieldAggregation::class . ' , got ' . get_class($aggregation));
35+
}
36+
37+
$searchFieldName = $this->fieldNameResolver->getAggregationFieldName(
38+
$aggregation->getContentTypeIdentifier(),
39+
$aggregation->getFieldDefinitionIdentifier(),
40+
$this->searchFieldName
41+
);
42+
43+
if ($searchFieldName === null) {
44+
throw new RuntimeException('No searchable fields found for the provided aggregation target');
45+
}
46+
47+
return $searchFieldName;
48+
}
49+
}

0 commit comments

Comments
 (0)