-
-
Notifications
You must be signed in to change notification settings - Fork 963
Expand file tree
/
Copy pathOrderExtension.php
More file actions
121 lines (105 loc) · 4.02 KB
/
OrderExtension.php
File metadata and controls
121 lines (105 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace ApiPlatform\Doctrine\Odm\Extension;
use ApiPlatform\Doctrine\Common\PropertyHelperTrait;
use ApiPlatform\Doctrine\Odm\PropertyHelperTrait as MongoDbOdmPropertyHelperTrait;
use ApiPlatform\Metadata\Operation;
use Doctrine\ODM\MongoDB\Aggregation\Builder;
use Doctrine\ODM\MongoDB\Aggregation\Stage\Search;
use Doctrine\ODM\MongoDB\Aggregation\Stage\Sort;
use Doctrine\Persistence\ManagerRegistry;
/**
* Applies selected ordering while querying resource collection.
*
* @author Kévin Dunglas <dunglas@gmail.com>
* @author Samuel ROZE <samuel.roze@gmail.com>
* @author Vincent Chalamon <vincentchalamon@gmail.com>
* @author Alan Poulain <contact@alanpoulain.eu>
*/
final class OrderExtension implements AggregationCollectionExtensionInterface
{
use MongoDbOdmPropertyHelperTrait;
use PropertyHelperTrait;
public function __construct(private readonly ?string $order = null, private readonly ?ManagerRegistry $managerRegistry = null)
{
}
/**
* {@inheritdoc}
*/
public function applyToCollection(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
{
// Do not apply order if already defined on $aggregationBuilder
if ($this->hasSortStage($aggregationBuilder)) {
return;
}
$classMetaData = $this->getClassMetadata($resourceClass);
$identifiers = $classMetaData->getIdentifier();
if (isset($context['operation'])) {
$defaultOrder = $context['operation']->getOrder() ?? [];
} else {
$defaultOrder = $operation?->getOrder();
}
if ($defaultOrder) {
foreach ($defaultOrder as $field => $order) {
if (\is_int($field)) {
// Default direction
$field = $order;
$order = 'ASC';
}
if ($this->isPropertyNested($field, $resourceClass)) {
[$field] = $this->addLookupsForNestedProperty($field, $aggregationBuilder, $resourceClass, true);
}
$context['mongodb_odm_sort_fields'] = ($context['mongodb_odm_sort_fields'] ?? []) + [$field => $order];
if ($this->isSearchPipeline($aggregationBuilder)) {
$aggregationBuilder->getStage(0)
->sort($context['mongodb_odm_sort_fields']);
} else {
$aggregationBuilder->sort($context['mongodb_odm_sort_fields']);
}
}
return;
}
if (null !== $this->order && !$this->isSearchPipeline($aggregationBuilder)) {
foreach ($identifiers as $identifier) {
$aggregationBuilder->sort(
$context['mongodb_odm_sort_fields'] = ($context['mongodb_odm_sort_fields'] ?? []) + [$identifier => $this->order]
);
}
}
}
protected function getManagerRegistry(): ManagerRegistry
{
return $this->managerRegistry;
}
private function hasSortStage(Builder $aggregationBuilder): bool
{
try {
for ($index = 0; true; ++$index) {
if ($aggregationBuilder->getStage($index) instanceof Sort) {
// If at least one stage is sort, then it has sorting
return true;
}
}
} catch (\OutOfRangeException) {
// There is no more stages on the aggregation builder
return false;
}
}
private function isSearchPipeline(Builder $aggregationBuilder): bool
{
try {
return $aggregationBuilder->getStage(0) instanceof Search;
} catch (\OutOfRangeException) {
// Empty pipeline
return false;
}
}
}