Passed
Push — master ( c6cb64...3f2e18 )
by Christian
11:15 queued 12s
created

hydrateTermsAggregation()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
nc 17
nop 3
dl 0
loc 36
rs 8.6666
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Elasticsearch\Framework\DataAbstractionLayer;
4
5
use Shopware\Core\Framework\Context;
6
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityAggregator;
7
use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
8
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
9
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Aggregation;
10
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\DateHistogramAggregation;
11
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
12
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\TermsAggregation;
13
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\AvgAggregation;
14
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\CountAggregation;
15
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\EntityAggregation;
16
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
17
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MinAggregation;
18
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\StatsAggregation;
19
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\SumAggregation;
20
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResult;
21
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
22
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Bucket\Bucket;
23
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Bucket\DateHistogramResult;
24
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Bucket\TermsResult;
25
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\AvgResult;
26
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\CountResult;
27
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\EntityResult;
28
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\MaxResult;
29
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\MinResult;
30
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\StatsResult;
31
use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\SumResult;
32
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
33
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
34
35
class ElasticsearchEntityAggregatorHydrator extends AbstractElasticsearchAggregationHydrator
36
{
37
    /**
38
     * @var DefinitionInstanceRegistry
39
     */
40
    private $definitionInstanceRegistry;
41
42
    public function __construct(
43
        DefinitionInstanceRegistry $definitionInstanceRegistry
44
    ) {
45
        $this->definitionInstanceRegistry = $definitionInstanceRegistry;
46
    }
47
48
    public function getDecorated(): AbstractElasticsearchAggregationHydrator
49
    {
50
        throw new DecorationPatternException(self::class);
51
    }
52
53
    public function hydrate(EntityDefinition $definition, Criteria $criteria, Context $context, array $result): AggregationResultCollection
54
    {
55
        if (!isset($result['aggregations'])) {
56
            return new AggregationResultCollection();
57
        }
58
59
        $aggregations = new AggregationResultCollection();
60
61
        foreach ($result['aggregations'] as $name => $aggResult) {
62
            $aggregation = $criteria->getAggregation($name);
63
64
            if (!$aggregation) {
65
                continue;
66
            }
67
68
            $aggregations->add(
69
                $this->hydrateAggregation($aggregation, $aggResult, $context)
70
            );
71
        }
72
73
        return $aggregations;
74
    }
75
76
    private function hydrateAggregation(Aggregation $aggregation, array $result, Context $context): AggregationResult
77
    {
78
        switch (true) {
79
            case $aggregation instanceof StatsAggregation:
80
                return new StatsResult($aggregation->getName(), $result['min'], $result['max'], $result['avg'], $result['sum']);
81
82
            case $aggregation instanceof AvgAggregation:
83
                return new AvgResult($aggregation->getName(), $result['value']);
84
85
            case $aggregation instanceof CountAggregation:
86
                return new CountResult($aggregation->getName(), $result['value']);
87
88
            case $aggregation instanceof EntityAggregation:
89
                return $this->hydrateEntityAggregation($aggregation, $result, $context);
90
91
            case $aggregation instanceof MaxAggregation:
92
                return new MaxResult($aggregation->getName(), $result['value']);
93
94
            case $aggregation instanceof MinAggregation:
95
                return new MinResult($aggregation->getName(), $result['value']);
96
97
            case $aggregation instanceof SumAggregation:
98
                return new SumResult($aggregation->getName(), $result['value']);
99
100
            case $aggregation instanceof FilterAggregation:
101
                $nested = $aggregation->getAggregation();
102
103
                if (!$nested) {
104
                    throw new \RuntimeException(sprintf('Filter aggregation %s contains no nested aggregation.', $aggregation->getName()));
105
                }
106
                $nestedResult = $result;
107
                if (isset($nestedResult[$aggregation->getName()])) {
108
                    $nestedResult = $nestedResult[$aggregation->getName()];
109
                }
110
111
                if (isset($nestedResult[$nested->getName()])) {
112
                    $nestedResult = $nestedResult[$nested->getName()];
113
                }
114
115
                return $this->hydrateAggregation($nested, $nestedResult, $context);
116
117
            case $aggregation instanceof DateHistogramAggregation:
118
                return $this->hydrateDateHistogram($aggregation, $result, $context);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateDat...ion, $result, $context) could return the type null which is incompatible with the type-hinted return Shopware\Core\Framework\...esult\AggregationResult. Consider adding an additional type-check to rule them out.
Loading history...
119
120
            case $aggregation instanceof TermsAggregation:
121
                return $this->hydrateTermsAggregation($aggregation, $result, $context);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateTer...ion, $result, $context) could return the type null which is incompatible with the type-hinted return Shopware\Core\Framework\...esult\AggregationResult. Consider adding an additional type-check to rule them out.
Loading history...
122
123
            default:
124
                throw new \RuntimeException(sprintf('Provided aggregation of class %s is not supported', \get_class($aggregation)));
125
        }
126
    }
127
128
    private function hydrateEntityAggregation(EntityAggregation $aggregation, array $result, Context $context): EntityResult
129
    {
130
        if (\array_key_exists($aggregation->getName(), $result)) {
131
            $result = $result[$aggregation->getName()];
132
        }
133
134
        $ids = array_column($result['buckets'], 'key');
135
136
        $repository = $this->definitionInstanceRegistry->getRepository($aggregation->getEntity());
137
138
        $entities = $repository->search(new Criteria($ids), $context);
139
140
        return new EntityResult($aggregation->getName(), $entities->getEntities());
141
    }
142
143
    private function hydrateDateHistogram(DateHistogramAggregation $aggregation, array $result, Context $context)
144
    {
145
        if (isset($result[$aggregation->getName()])) {
146
            $result = $result[$aggregation->getName()];
147
        }
148
149
        if (!isset($result['buckets'])) {
150
            return null;
151
        }
152
153
        $buckets = [];
154
        foreach ($result['buckets'] as $bucket) {
155
            $nested = null;
156
157
            $nestedAggregation = $aggregation->getAggregation();
158
            if ($nestedAggregation) {
159
                $nested = $this->hydrateAggregation($nestedAggregation, $bucket[$nestedAggregation->getName()], $context);
160
            }
161
162
            $key = $bucket['key'][$aggregation->getName() . '.key'];
163
164
            $date = new \DateTime($key);
165
166
            if ($aggregation->getFormat()) {
167
                $value = $date->format($aggregation->getFormat());
168
            } else {
169
                $value = EntityAggregator::formatDate($aggregation->getInterval(), $date);
170
            }
171
172
            $buckets[] = new Bucket($value, $bucket['doc_count'], $nested);
173
        }
174
175
        return new DateHistogramResult($aggregation->getName(), $buckets);
176
    }
177
178
    private function hydrateTermsAggregation(TermsAggregation $aggregation, array $result, Context $context): ?TermsResult
179
    {
180
        if ($aggregation->getSorting()) {
181
            return $this->hydrateSortedTermsAggregation($aggregation, $result, $context);
182
        }
183
184
        if (isset($result[$aggregation->getName()])) {
185
            $result = $result[$aggregation->getName()];
186
        }
187
188
        $key = $aggregation->getName() . '.key';
189
        if (isset($result[$key])) {
190
            $result = $result[$key];
191
        }
192
193
        if (!isset($result['buckets'])) {
194
            return null;
195
        }
196
197
        $buckets = [];
198
        foreach ($result['buckets'] as $bucket) {
199
            $nested = null;
200
201
            $nestedAggregation = $aggregation->getAggregation();
202
            if ($nestedAggregation) {
203
                $nested = $this->hydrateAggregation(
204
                    $nestedAggregation,
205
                    $bucket[$nestedAggregation->getName()],
206
                    $context
207
                );
208
            }
209
210
            $buckets[] = new Bucket((string) $bucket['key'], $bucket['doc_count'], $nested);
211
        }
212
213
        return new TermsResult($aggregation->getName(), $buckets);
214
    }
215
216
    private function hydrateSortedTermsAggregation(TermsAggregation $aggregation, array $result, Context $context): ?TermsResult
217
    {
218
        if (isset($result[$aggregation->getName()])) {
219
            $result = $result[$aggregation->getName()];
220
        }
221
222
        if (!isset($result['buckets'])) {
223
            return null;
224
        }
225
226
        $buckets = [];
227
        foreach ($result['buckets'] as $bucket) {
228
            $nested = null;
229
230
            $nestedAggregation = $aggregation->getAggregation();
231
            if ($nestedAggregation) {
232
                $nested = $this->hydrateAggregation(
233
                    $nestedAggregation,
234
                    $bucket[$nestedAggregation->getName()],
235
                    $context
236
                );
237
            }
238
239
            $key = $bucket['key'][$aggregation->getName() . '.key'];
240
241
            $buckets[] = new Bucket((string) $key, $bucket['doc_count'], $nested);
242
        }
243
244
        return new TermsResult($aggregation->getName(), $buckets);
245
    }
246
}
247