Passed
Push — improve-filter-message ( b945de...00229f )
by Han Hui
04:37
created

PaginationExtension::getResult()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 4
dl 0
loc 8
rs 10
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension;
15
16
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Paginator;
17
use ApiPlatform\Core\DataProvider\Pagination;
18
use ApiPlatform\Core\Exception\RuntimeException;
19
use Doctrine\Common\Persistence\ManagerRegistry;
20
use Doctrine\ODM\MongoDB\Aggregation\Builder;
21
use Doctrine\ODM\MongoDB\DocumentManager;
22
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
23
24
/**
25
 * Applies pagination on the Doctrine aggregation for resource collection when enabled.
26
 *
27
 * @experimental
28
 *
29
 * @author Kévin Dunglas <[email protected]>
30
 * @author Samuel ROZE <[email protected]>
31
 * @author Alan Poulain <[email protected]>
32
 */
33
final class PaginationExtension implements AggregationResultCollectionExtensionInterface
34
{
35
    private $managerRegistry;
36
    private $pagination;
37
38
    public function __construct(ManagerRegistry $managerRegistry, Pagination $pagination)
39
    {
40
        $this->managerRegistry = $managerRegistry;
41
        $this->pagination = $pagination;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     *
47
     * @throws RuntimeException
48
     */
49
    public function applyToCollection(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array &$context = [])
50
    {
51
        if (!$this->pagination->isEnabled($resourceClass, $operationName, $context)) {
52
            return;
53
        }
54
55
        [, $offset, $limit] = $this->pagination->getPagination($resourceClass, $operationName, $context);
56
57
        $manager = $this->managerRegistry->getManagerForClass($resourceClass);
58
        if (!$manager instanceof DocumentManager) {
59
            throw new RuntimeException(sprintf('The manager for "%s" must be an instance of "%s".', $resourceClass, DocumentManager::class));
60
        }
61
62
        $repository = $manager->getRepository($resourceClass);
63
        if (!$repository instanceof DocumentRepository) {
64
            throw new RuntimeException(sprintf('The repository for "%s" must be an instance of "%s".', $resourceClass, DocumentRepository::class));
65
        }
66
67
        $resultsAggregationBuilder = $repository->createAggregationBuilder()->skip($offset);
68
        if ($limit > 0) {
69
            $resultsAggregationBuilder->limit($limit);
70
        } else {
71
            // Results have to be 0 but MongoDB does not support a limit equal to 0.
72
            $resultsAggregationBuilder->match()->field(Paginator::LIMIT_ZERO_MARKER_FIELD)->equals(Paginator::LIMIT_ZERO_MARKER);
73
        }
74
75
        $aggregationBuilder
76
            ->facet()
77
            ->field('results')->pipeline(
78
                $resultsAggregationBuilder
79
            )
80
            ->field('count')->pipeline(
81
                $repository->createAggregationBuilder()
82
                    ->count('count')
83
            );
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    public function supportsResult(string $resourceClass, string $operationName = null, array $context = []): bool
90
    {
91
        return $this->pagination->isEnabled($resourceClass, $operationName, $context);
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     *
97
     * @throws RuntimeException
98
     */
99
    public function getResult(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array $context = [])
100
    {
101
        $manager = $this->managerRegistry->getManagerForClass($resourceClass);
102
        if (!$manager instanceof DocumentManager) {
103
            throw new RuntimeException(sprintf('The manager for "%s" must be an instance of "%s".', $resourceClass, DocumentManager::class));
104
        }
105
106
        return new Paginator($aggregationBuilder->execute(), $manager->getUnitOfWork(), $resourceClass, $aggregationBuilder->getPipeline());
107
    }
108
}
109