Passed
Push — master ( e9610e...a5c3f4 )
by Alexander
06:50
created

OffsetPaginator::read()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.1406

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 12
ccs 6
cts 8
cp 0.75
crap 3.1406
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Data\Paginator;
6
7
use Yiisoft\Data\Reader\CountableDataInterface;
8
use Yiisoft\Data\Reader\DataReaderInterface;
9
use Yiisoft\Data\Reader\OffsetableDataInterface;
10
11
final class OffsetPaginator implements PaginatorInterface
12
{
13
    /** @var OffsetableDataInterface|DataReaderInterface|CountableDataInterface */
14
    private DataReaderInterface $dataReader;
15
    private int $currentPage = 1;
16
    private int $pageSize = self::DEFAULT_PAGE_SIZE;
17
    private ?DataReaderInterface $cachedReader = null;
18
19 23
    public function __construct(DataReaderInterface $dataReader)
20
    {
21 23
        if (!$dataReader instanceof OffsetableDataInterface) {
22 1
            throw new \InvalidArgumentException(
23 1
                sprintf(
24 1
                    'Data reader should implement %s in order to be used with offset paginator',
25
                    OffsetableDataInterface::class
26
                )
27
            );
28
        }
29
30 22
        if (!$dataReader instanceof CountableDataInterface) {
31 1
            throw new \InvalidArgumentException(
32 1
                sprintf(
33 1
                    'Data reader should implement %s in order to be used with offset paginator',
34
                    CountableDataInterface::class
35
                )
36
            );
37
        }
38
39 21
        $this->dataReader = $dataReader;
40
    }
41
42 3
    public function isRequired(): bool
43
    {
44 3
        return $this->getTotalPages() > 1;
45
    }
46
47 3
    public function getCurrentPage(): int
48
    {
49 3
        return $this->currentPage;
50
    }
51
52 12
    public function withCurrentPage(int $page): self
53
    {
54 12
        if ($page < 1) {
55 1
            throw new PaginatorException('Current page should be at least 1');
56
        }
57 11
        $new = clone $this;
58 11
        $new->currentPage = $page;
59 11
        $new->cachedReader = null;
60 11
        return $new;
61
    }
62
63 16
    public function withPageSize(int $size): self
64
    {
65 16
        if ($size < 1) {
66 1
            throw new PaginatorException('Page size should be at least 1');
67
        }
68 15
        $new = clone $this;
69 15
        $new->pageSize = $size;
70 15
        $new->cachedReader = null;
71 15
        return $new;
72
    }
73
74 4
    public function isOnFirstPage(): bool
75
    {
76 4
        return $this->currentPage === 1;
77
    }
78
79 4
    public function isOnLastPage(): bool
80
    {
81 4
        if ($this->currentPage > $this->getInternalTotalPages()) {
82 1
            throw new PaginatorException('Page not found');
83
        }
84 3
        return $this->currentPage === $this->getInternalTotalPages();
85
    }
86
87 14
    public function getTotalPages(): int
88
    {
89 14
        return (int) ceil($this->getTotalItems() / $this->pageSize);
90
    }
91
92 6
    public function getOffset(): int
93
    {
94 6
        return $this->pageSize * ($this->currentPage - 1);
95
    }
96
97 5
    public function read(): iterable
98
    {
99 5
        if ($this->cachedReader !== null) {
100
            yield from $this->cachedReader->read();
101
            return;
102
        }
103 5
        if ($this->currentPage > $this->getInternalTotalPages()) {
104 1
            throw new PaginatorException('Page not found');
105
        }
106
        /** @var OffsetableDataInterface|DataReaderInterface|CountableDataInterface $reader */
107 4
        $this->cachedReader = $this->dataReader->withLimit($this->pageSize)->withOffset($this->getOffset());
0 ignored issues
show
Bug introduced by
The method withOffset() does not exist on Yiisoft\Data\Reader\DataReaderInterface. It seems like you code against a sub-type of Yiisoft\Data\Reader\DataReaderInterface such as anonymous//tests/Paginat...fsetPaginatorTest.php$1 or Yiisoft\Data\Reader\Iterable\IterableDataReader. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
        $this->cachedReader = $this->dataReader->withLimit($this->pageSize)->/** @scrutinizer ignore-call */ withOffset($this->getOffset());
Loading history...
108 4
        yield from $this->cachedReader->read();
0 ignored issues
show
Bug introduced by
The method read() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
        yield from $this->cachedReader->/** @scrutinizer ignore-call */ read();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
109
    }
110
111
    public function getNextPageToken(): ?string
112
    {
113
        return $this->isOnLastPage() ? null : (string) ($this->currentPage + 1);
114
    }
115
116
    public function getPreviousPageToken(): ?string
117
    {
118
        return $this->isOnFirstPage() ? null : (string) ($this->currentPage - 1);
119
    }
120
121
    public function withNextPageToken(?string $token): self
122
    {
123
        return $this->withCurrentPage((int)$token);
124
    }
125
126
    public function withPreviousPageToken(?string $token): self
127
    {
128
        return $this->withCurrentPage((int)$token);
129
    }
130
131 4
    public function getCurrentPageSize(): int
132
    {
133 4
        $pages = $this->getInternalTotalPages();
134 4
        if ($pages === 1) {
135 2
            return $this->getTotalItems();
136
        }
137 2
        if ($this->currentPage === $pages) {
138 1
            return $this->getTotalItems() - $this->getOffset();
139
        }
140 1
        if ($this->currentPage > $pages) {
141
            throw new PaginatorException('Page not found');
142
        }
143 1
        return $this->pageSize;
144
    }
145
146 15
    public function getTotalItems(): int
147
    {
148 15
        return $this->dataReader->count();
0 ignored issues
show
Bug introduced by
The method count() does not exist on Yiisoft\Data\Reader\DataReaderInterface. It seems like you code against a sub-type of said class. However, the method does not exist in anonymous//tests/Paginat...ysetPaginatorTest.php$2 or anonymous//tests/Paginat...ysetPaginatorTest.php$1. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

148
        return $this->dataReader->/** @scrutinizer ignore-call */ count();
Loading history...
149
    }
150
151 1
    public function getPageSize(): int
152
    {
153 1
        return $this->pageSize;
154
    }
155
156 11
    private function getInternalTotalPages(): int
157
    {
158 11
        return max(1, $this->getTotalPages());
159
    }
160
}
161