• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 10943429050

19 Sep 2024 02:48PM UTC coverage: 7.647% (-0.03%) from 7.675%
10943429050

push

github

web-flow
feat: api-platform/json-hal component (#6621)

* feat: add hal support for laravel

* feat: quick review

* fix: typo & cs-fixer

* fix: typo in composer.json

* fix: cs-fixer & phpstan

* fix: forgot about hal item normalizer, therefore there's no more createbook nor updatebook test as Hal is a readonly format

0 of 94 new or added lines in 2 files covered. (0.0%)

9082 existing lines in 291 files now uncovered.

12629 of 165144 relevant lines covered (7.65%)

22.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.0
/src/Doctrine/Odm/Paginator.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\Doctrine\Odm;
15

16
use ApiPlatform\Metadata\Exception\InvalidArgumentException;
17
use ApiPlatform\State\Pagination\HasNextPagePaginatorInterface;
18
use ApiPlatform\State\Pagination\PaginatorInterface;
19
use Doctrine\ODM\MongoDB\Iterator\Iterator;
20
use Doctrine\ODM\MongoDB\UnitOfWork;
21

22
/**
23
 * Decorates the Doctrine MongoDB ODM paginator.
24
 *
25
 * @author Kévin Dunglas <dunglas@gmail.com>
26
 * @author Alan Poulain <contact@alanpoulain.eu>
27
 */
28
final class Paginator implements \IteratorAggregate, PaginatorInterface, HasNextPagePaginatorInterface
29
{
30
    public const LIMIT_ZERO_MARKER_FIELD = '___';
31
    public const LIMIT_ZERO_MARKER = 'limit0';
32

33
    private ?\ArrayIterator $iterator = null;
34

35
    private readonly int $firstResult;
36

37
    private readonly int $maxResults;
38

39
    private readonly int $totalItems;
40

41
    public function __construct(private readonly Iterator $mongoDbOdmIterator, private readonly UnitOfWork $unitOfWork, private readonly string $resourceClass, private readonly array $pipeline)
42
    {
UNCOV
43
        $resultsFacetInfo = $this->getFacetInfo('results');
538✔
UNCOV
44
        $this->getFacetInfo('count');
538✔
45

46
        /*
47
         * Since the {@see \MongoDB\Driver\Cursor} class does not expose information about
48
         * skip/limit parameters of the query, the values set in the facet stage are used instead.
49
         */
UNCOV
50
        $this->firstResult = $this->getStageInfo($resultsFacetInfo, '$skip');
538✔
UNCOV
51
        $this->maxResults = $this->hasLimitZeroStage($resultsFacetInfo) ? 0 : $this->getStageInfo($resultsFacetInfo, '$limit');
538✔
UNCOV
52
        $this->totalItems = $mongoDbOdmIterator->toArray()[0]['count'][0]['count'] ?? 0;
538✔
53
    }
54

55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function getCurrentPage(): float
59
    {
UNCOV
60
        if (0 >= $this->maxResults) {
404✔
UNCOV
61
            return 1.;
2✔
62
        }
63

UNCOV
64
        return floor($this->firstResult / $this->maxResults) + 1.;
402✔
65
    }
66

67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function getLastPage(): float
71
    {
UNCOV
72
        if (0 >= $this->maxResults) {
402✔
UNCOV
73
            return 1.;
2✔
74
        }
75

UNCOV
76
        return ceil($this->totalItems / $this->maxResults) ?: 1.;
400✔
77
    }
78

79
    /**
80
     * {@inheritdoc}
81
     */
82
    public function getItemsPerPage(): float
83
    {
UNCOV
84
        return (float) $this->maxResults;
90✔
85
    }
86

87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function getTotalItems(): float
91
    {
UNCOV
92
        return (float) $this->totalItems;
410✔
93
    }
94

95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function getIterator(): \Traversable
99
    {
UNCOV
100
        return $this->iterator ?? $this->iterator = new \ArrayIterator(array_map(fn ($result): object => $this->unitOfWork->getOrCreateDocument($this->resourceClass, $result), $this->mongoDbOdmIterator->toArray()[0]['results']));
514✔
101
    }
102

103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function count(): int
107
    {
UNCOV
108
        return is_countable($this->mongoDbOdmIterator->toArray()[0]['results']) ? \count($this->mongoDbOdmIterator->toArray()[0]['results']) : 0;
12✔
109
    }
110

111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function hasNextPage(): bool
115
    {
UNCOV
116
        return $this->getLastPage() > $this->getCurrentPage();
6✔
117
    }
118

119
    /**
120
     * @throws InvalidArgumentException
121
     */
122
    private function getFacetInfo(string $field): array
123
    {
UNCOV
124
        foreach ($this->pipeline as $indexStage => $infoStage) {
538✔
UNCOV
125
            if (\array_key_exists('$facet', $infoStage)) {
538✔
UNCOV
126
                if (!isset($this->pipeline[$indexStage]['$facet'][$field])) {
538✔
127
                    throw new InvalidArgumentException("\"$field\" facet was not applied to the aggregation pipeline.");
×
128
                }
129

UNCOV
130
                return $this->pipeline[$indexStage]['$facet'][$field];
538✔
131
            }
132
        }
133

134
        throw new InvalidArgumentException('$facet stage was not applied to the aggregation pipeline.');
×
135
    }
136

137
    /**
138
     * @throws InvalidArgumentException
139
     */
140
    private function getStageInfo(array $resultsFacetInfo, string $stage): int
141
    {
UNCOV
142
        foreach ($resultsFacetInfo as $resultFacetInfo) {
538✔
UNCOV
143
            if (isset($resultFacetInfo[$stage])) {
538✔
UNCOV
144
                return $resultFacetInfo[$stage];
538✔
145
            }
146
        }
147

148
        throw new InvalidArgumentException("$stage stage was not applied to the facet stage of the aggregation pipeline.");
×
149
    }
150

151
    private function hasLimitZeroStage(array $resultsFacetInfo): bool
152
    {
UNCOV
153
        foreach ($resultsFacetInfo as $resultFacetInfo) {
538✔
UNCOV
154
            if (self::LIMIT_ZERO_MARKER === ($resultFacetInfo['$match'][self::LIMIT_ZERO_MARKER_FIELD] ?? null)) {
538✔
UNCOV
155
                return true;
4✔
156
            }
157
        }
158

UNCOV
159
        return false;
536✔
160
    }
161
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc