Passed
Pull Request — master (#24)
by
unknown
02:14
created

OffsetPaginator   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Test Coverage

Coverage 63.33%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 47
c 1
b 0
f 0
dl 0
loc 138
ccs 38
cts 60
cp 0.6333
rs 10

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 3
A getCurrentPage() 0 3 1
A read() 0 7 2
A __clone() 0 4 1
A isOnFirstPage() 0 3 1
A withPreviousPageToken() 0 3 1
A withPageSize() 0 9 2
A initializeInternal() 0 10 3
A withNextPageToken() 0 3 1
A getNextPageToken() 0 3 2
A withCurrentPage() 0 9 2
A getOffset() 0 3 1
A getPreviousPageToken() 0 3 2
A getCurrentPageSize() 0 4 1
A isOnLastPage() 0 3 1
A getTotalPages() 0 7 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Yiisoft\Data\Paginator;
5
6
use Yiisoft\Data\Reader\CountableDataInterface;
7
use Yiisoft\Data\Reader\DataReaderInterface;
8
use Yiisoft\Data\Reader\OffsetableDataInterface;
9
10
/**
11
 * OffsetPaginator
12
 */
13
final class OffsetPaginator implements PaginatorInterface
14
{
15
    /**
16
     * @var OffsetableDataInterface|DataReaderInterface|CountableDataInterface
17
     */
18
    private $dataReader;
19
20
    private $currentPage = 1;
21
    private $pageSize = self::DEFAULT_PAGE_SIZE;
22
23
    /**
24
     * @var array|null Reader cache against repeated scans.
25
     *
26
     * @see initializeInternal()
27
     */
28
    private $readCache;
29
    /**
30
     * @var int|null Total count cache against repeated scans.
31
     *
32
     * See more {@see initializeInternal()}.
33
     */
34
    private $totalCountCache;
35
36 11
    public function __construct(DataReaderInterface $dataReader)
37
    {
38 11
        if (!$dataReader instanceof OffsetableDataInterface) {
39 1
            throw new \InvalidArgumentException('Data reader should implement OffsetableDataInterface in order to be used with offset paginator');
40
        }
41
42 10
        if (!$dataReader instanceof CountableDataInterface) {
43
            throw new \InvalidArgumentException('Data reader should implement CountableDataInterface in order to be used with offset paginator');
44
        }
45
46 10
        $this->dataReader = $dataReader;
47 10
    }
48
49
    public function getCurrentPage(): int
50
    {
51
        return $this->currentPage;
52
    }
53
54 8
    public function withCurrentPage(int $page)
55
    {
56 8
        if ($page < 1) {
57 1
            throw new \InvalidArgumentException('Current page should be at least 1');
58
        }
59
60 7
        $new = clone $this;
61 7
        $new->currentPage = $page;
62 7
        return $new;
63
    }
64
65 9
    public function withPageSize(int $size)
66
    {
67 9
        if ($size < 1) {
68 1
            throw new \InvalidArgumentException('Page size should be at least 1');
69
        }
70
71 8
        $new = clone $this;
72 8
        $new->pageSize = $size;
73 8
        return $new;
74
    }
75
76 2
    public function isOnFirstPage(): bool
77
    {
78 2
        return $this->currentPage === 1;
79
    }
80
81 2
    public function isOnLastPage(): bool
82
    {
83 2
        return $this->currentPage === $this->getTotalPages();
84
    }
85
86 3
    public function getTotalPages(): int
87
    {
88 3
        $totalCount = $this->totalCountCache;
89 3
        if($totalCount === null) {
90 3
            $totalCount = $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 Yiisoft\Data\Reader\DataReaderInterface such as Yiisoft\Data\Reader\IterableDataReader. ( Ignorable by Annotation )

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

90
            /** @scrutinizer ignore-call */ 
91
            $totalCount = $this->dataReader->count();
Loading history...
Bug introduced by
The method count() does not exist on Yiisoft\Data\Reader\OffsetableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\OffsetableDataInterface. ( Ignorable by Annotation )

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

90
            /** @scrutinizer ignore-call */ 
91
            $totalCount = $this->dataReader->count();
Loading history...
91
        }
92 3
        return (int) ceil($totalCount / $this->pageSize);
93
    }
94
95 3
    private function getOffset(): int
96
    {
97 3
        return $this->pageSize * ($this->currentPage - 1);
98
    }
99
100 3
    public function read(): iterable
101
    {
102 3
        if($this->readCache !== null) {
103
            return $this->readCache;
104
        }
105 3
        $reader = $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 Yiisoft\Data\Reader\IterableDataReader. ( Ignorable by Annotation )

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

105
        $reader = $this->dataReader->withLimit($this->pageSize)->/** @scrutinizer ignore-call */ withOffset($this->getOffset());
Loading history...
Bug introduced by
The method withOffset() does not exist on Yiisoft\Data\Reader\CountableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\CountableDataInterface. ( Ignorable by Annotation )

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

105
        $reader = $this->dataReader->withLimit($this->pageSize)->/** @scrutinizer ignore-call */ withOffset($this->getOffset());
Loading history...
Bug introduced by
The method withLimit() does not exist on Yiisoft\Data\Reader\OffsetableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\OffsetableDataInterface. ( Ignorable by Annotation )

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

105
        $reader = $this->dataReader->/** @scrutinizer ignore-call */ withLimit($this->pageSize)->withOffset($this->getOffset());
Loading history...
Bug introduced by
The method withLimit() does not exist on Yiisoft\Data\Reader\CountableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\CountableDataInterface. ( Ignorable by Annotation )

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

105
        $reader = $this->dataReader->/** @scrutinizer ignore-call */ withLimit($this->pageSize)->withOffset($this->getOffset());
Loading history...
106 3
        yield from $reader->read();
0 ignored issues
show
Bug introduced by
The method read() does not exist on Yiisoft\Data\Reader\OffsetableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\OffsetableDataInterface. ( Ignorable by Annotation )

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

106
        yield from $reader->/** @scrutinizer ignore-call */ read();
Loading history...
Bug introduced by
The method read() does not exist on Yiisoft\Data\Reader\CountableDataInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Data\Reader\CountableDataInterface. ( Ignorable by Annotation )

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

106
        yield from $reader->/** @scrutinizer ignore-call */ read();
Loading history...
107 3
    }
108
109
    public function getNextPageToken(): ?string
110
    {
111
        return $this->isOnLastPage() ? null : (string) ($this->currentPage + 1);
112
    }
113
114
    public function getPreviousPageToken(): ?string
115
    {
116
        return $this->isOnFirstPage() ? null : (string) ($this->currentPage - 1);
117
    }
118
119
    public function withNextPageToken(?string $token)
120
    {
121
        return $this->withCurrentPage(intval($token));
122
    }
123
124
    public function withPreviousPageToken(?string $token)
125
    {
126
        return $this->withCurrentPage(intval($token));
127
    }
128
129
    public function getCurrentPageSize(): int
130
    {
131
        $this->initializeInternal();
132
        return count($this->readCache);
133
    }
134
135 8
    public function __clone()
136
    {
137 8
        $this->readCache = null;
138 8
        $this->totalCountCache = null;
139 8
    }
140
141
    protected function initializeInternal(): void
142
    {
143
        if($this->readCache !== null) {
144
            return;
145
        }
146
        $cache = [];
147
        foreach ($this->read() as $value) {
148
            $cache[] = $value;
149
        }
150
        $this->readCache = $cache;
151
    }
152
}
153