LinkHeaderAwarePagination::parseLinkHeader()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
nc 4
nop 2
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cerbero\LazyJsonPages\Paginations;
6
7
use Cerbero\LazyJsonPages\Concerns\YieldsItemsByCursor;
8
use Cerbero\LazyJsonPages\Concerns\YieldsItemsByLength;
9
use Generator;
10
use Psr\Http\Message\ResponseInterface;
11
use Traversable;
12
13
/**
14
 * The pagination using a Link header.
15
 */
16
class LinkHeaderAwarePagination extends Pagination
17
{
18
    use YieldsItemsByCursor;
0 ignored issues
show
introduced by
The trait Cerbero\LazyJsonPages\Concerns\YieldsItemsByCursor requires some properties which are not provided by Cerbero\LazyJsonPages\Pa...nkHeaderAwarePagination: $attempts, $backoff, $rateLimits
Loading history...
19
    use YieldsItemsByLength;
0 ignored issues
show
introduced by
The trait Cerbero\LazyJsonPages\Concerns\YieldsItemsByLength requires some properties which are not provided by Cerbero\LazyJsonPages\Pa...nkHeaderAwarePagination: $attempts, $backoff, $firstPage, $async, $rateLimits
Loading history...
20
21
    /**
22
     * The Link header format.
23
     */
24
    public const FORMAT = '~<\s*(?<uri>[^\s>]+)\s*>.*?"\s*(?<rel>[^\s"]+)\s*"~';
25
26
    /**
27
     * Determine whether this pagination matches the configuration.
28
     */
29 38
    public function matches(): bool
30
    {
31 38
        return $this->config->hasLinkHeader
32 38
            && $this->config->totalItemsKey === null
33 38
            && $this->config->totalPagesKey === null
34 38
            && $this->config->lastPageKey === null;
35
    }
36
37
    /**
38
     * Yield the paginated items.
39
     *
40
     * @return Traversable<int, mixed>
41
     */
42 4
    public function getIterator(): Traversable
43
    {
44
        /** @var array{last?: int, next?: string|int} */
45 4
        $links = $this->parseLinkHeader($this->source->response()->getHeaderLine('link'));
46
47
        yield from match (true) {
48 4
            isset($links['last']) => $this->yieldItemsByLastPage($links['last']),
49 2
            isset($links['next']) => $this->yieldItemsByNextLink(),
50 1
            default => $this->yieldItemsFrom($this->source->pullResponse()),
51
        };
52
    }
53
54
    /**
55
     * Retrieve the parsed Link header.
56
     *
57
     * @template TRelation of string|null
58
     *
59
     * @param TRelation $relation
0 ignored issues
show
Bug introduced by
The type Cerbero\LazyJsonPages\Paginations\TRelation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
60
     * @return (TRelation is null ? array<string, int|string|null> : string|int|null)
0 ignored issues
show
Documentation Bug introduced by
The doc comment (TRelation at position 1 could not be parsed: Expected ')' at position 1, but found 'TRelation'.
Loading history...
61
     */
62 4
    protected function parseLinkHeader(string $linkHeader, ?string $relation = null): array|string|int|null
63
    {
64 4
        $links = [];
65
66 4
        preg_match_all(static::FORMAT, $linkHeader, $matches, PREG_SET_ORDER);
67
68 4
        foreach ($matches as $match) {
69 3
            $links[$match['rel']] = $this->toPage($match['uri'], $match['rel'] != 'next');
70
        }
71
72 4
        return $relation ? ($links[$relation] ?? null) : $links;
73
    }
74
75
    /**
76
     * Yield the paginated items by the given last page.
77
     *
78
     * @return Generator<int, mixed>
79
     */
80 2
    protected function yieldItemsByLastPage(int $lastPage): Generator
81
    {
82 2
        yield from $this->yieldItemsUntilPage(function (ResponseInterface $response) use ($lastPage) {
83 2
            yield from $this->yieldItemsFrom($response);
84
85 2
            return $this->config->firstPage === 0 ? $lastPage + 1 : $lastPage;
86 2
        });
87
    }
88
89
    /**
90
     * Yield the paginated items by the given next link.
91
     *
92
     * @return Generator<int, mixed>
93
     */
94 1
    protected function yieldItemsByNextLink(): Generator
95
    {
96 1
        yield from $this->yieldItemsByCursor(function (ResponseInterface $response) {
97 1
            yield from $this->yieldItemsFrom($response);
98
99 1
            return $this->parseLinkHeader($response->getHeaderLine('link'), 'next');
100 1
        });
101
    }
102
}
103