Paginator   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 58
dl 0
loc 195
rs 9.52
c 0
b 0
f 0
wmc 36

23 Methods

Rating   Name   Duplication   Size   Complexity  
A currentPage() 0 3 1
A getPaginatedItems() 0 3 1
A __construct() 0 12 3
A generate() 0 3 1
A setCurrentPage() 0 7 1
A nextPageNumber() 0 7 2
A previous() 0 11 3
A canNavigateForward() 0 3 1
A formatLink() 0 3 1
A next() 0 11 3
A getRoute() 0 3 1
A hasMultiplePages() 0 3 1
A firstPage() 0 3 1
A formatPageName() 0 3 1
A canNavigateBack() 0 3 1
A firstItemNumberOnPage() 0 3 1
A totalPages() 0 3 1
A perPage() 0 3 1
A previousPageNumber() 0 7 2
A validateCurrentPageValue() 0 8 3
A lastPage() 0 3 1
A getItemsForPage() 0 6 1
A getPageLinks() 0 17 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Support;
6
7
use Hyde\Hyde;
8
use InvalidArgumentException;
9
use Hyde\Support\Models\Route;
10
use Hyde\Foundation\Facades\Routes;
11
use Illuminate\Support\Collection;
12
use Illuminate\Contracts\Support\Arrayable;
13
14
use function collect;
15
use function sprintf;
16
use function range;
17
18
class Paginator
19
{
20
    protected Collection $paginatedItems;
21
22
    protected int $pageSize = 25;
23
    protected int $currentPage = 1;
24
25
    /**
26
     * Optionally provide a route basename to be used in generating the pagination links.
27
     */
28
    protected string $routeBasename;
29
30
    public function __construct(Arrayable|array $items = [], int $pageSize = 25, ?int $currentPageNumber = null, ?string $paginationRouteBasename = null)
31
    {
32
        $this->pageSize = $pageSize;
33
34
        $this->generate(collect($items));
0 ignored issues
show
Bug introduced by
$items of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

34
        $this->generate(collect(/** @scrutinizer ignore-type */ $items));
Loading history...
35
36
        if ($currentPageNumber) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $currentPageNumber of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
37
            $this->setCurrentPage($currentPageNumber);
38
        }
39
40
        if ($paginationRouteBasename) {
41
            $this->routeBasename = $paginationRouteBasename;
42
        }
43
    }
44
45
    protected function generate(Collection $items): void
46
    {
47
        $this->paginatedItems = $items->chunk($this->perPage());
48
    }
49
50
    /** Set the current page number. */
51
    public function setCurrentPage(int $currentPage): Paginator
52
    {
53
        $this->validateCurrentPageValue($currentPage);
54
55
        $this->currentPage = $currentPage;
56
57
        return $this;
58
    }
59
60
    /** Get the current page number (which is used as a cursor). */
61
    public function currentPage(): int
62
    {
63
        return $this->currentPage;
64
    }
65
66
    /** Get the paginated collection */
67
    public function getPaginatedItems(): Collection
68
    {
69
        return $this->paginatedItems;
70
    }
71
72
    public function getItemsForPage(): Collection
73
    {
74
        /** @var Collection $paginated */
75
        $paginated = $this->paginatedItems->get($this->currentPage - 1);
76
77
        return $paginated;
78
    }
79
80
    public function getPageLinks(): array
81
    {
82
        $array = [];
83
84
        $pageRange = range(1, $this->totalPages());
85
86
        if (isset($this->routeBasename)) {
87
            foreach ($pageRange as $number) {
88
                $array[$number] = Routes::get("$this->routeBasename/page-$number") ?? Hyde::formatLink("$this->routeBasename/page-$number");
0 ignored issues
show
Bug introduced by
The method formatLink() does not exist on Hyde\Hyde. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

88
                $array[$number] = Routes::get("$this->routeBasename/page-$number") ?? Hyde::/** @scrutinizer ignore-call */ formatLink("$this->routeBasename/page-$number");
Loading history...
89
            }
90
        } else {
91
            foreach ($pageRange as $number) {
92
                $array[$number] = Hyde::formatLink("page-$number.html");
93
            }
94
        }
95
96
        return $array;
97
    }
98
99
    /** The number of items to be shown per page. */
100
    public function perPage(): int
101
    {
102
        return $this->pageSize;
103
    }
104
105
    /** Get the total number of pages. */
106
    public function totalPages(): int
107
    {
108
        return $this->paginatedItems->count();
109
    }
110
111
    /** Determine if there are enough items to split into multiple pages. */
112
    public function hasMultiplePages(): bool
113
    {
114
        return $this->totalPages() > 1;
115
    }
116
117
    /** Get the page number of the last available page. */
118
    public function lastPage(): int
119
    {
120
        return $this->totalPages();
121
    }
122
123
    /** Determine if there are fewer items after the cursor in the data store. */
124
    public function canNavigateBack(): bool
125
    {
126
        return $this->currentPage > $this->firstPage();
127
    }
128
129
    /** Determine if there are more items after the cursor in the data store. */
130
    public function canNavigateForward(): bool
131
    {
132
        return $this->currentPage < $this->lastPage();
133
    }
134
135
    public function previousPageNumber(): false|int
136
    {
137
        if (! $this->canNavigateBack()) {
138
            return false;
139
        }
140
141
        return $this->currentPage - 1;
142
    }
143
144
    public function nextPageNumber(): false|int
145
    {
146
        if (! $this->canNavigateForward()) {
147
            return false;
148
        }
149
150
        return $this->currentPage + 1;
151
    }
152
153
    public function previous(): false|string|Route
154
    {
155
        if (! $this->canNavigateBack()) {
156
            return false;
157
        }
158
159
        if (! isset($this->routeBasename)) {
160
            return $this->formatLink(-1);
161
        }
162
163
        return $this->getRoute(-1);
164
    }
165
166
    public function next(): false|string|Route
167
    {
168
        if (! $this->canNavigateForward()) {
169
            return false;
170
        }
171
172
        if (! isset($this->routeBasename)) {
173
            return $this->formatLink(+1);
174
        }
175
176
        return $this->getRoute(+1);
177
    }
178
179
    public function firstItemNumberOnPage(): int
180
    {
181
        return (($this->currentPage - 1) * $this->perPage()) + 1;
182
    }
183
184
    protected function validateCurrentPageValue(int $currentPage): void
185
    {
186
        if ($currentPage < $this->firstPage()) {
187
            throw new InvalidArgumentException('Current page number must be greater than 0.');
188
        }
189
190
        if ($currentPage > $this->lastPage()) {
191
            throw new InvalidArgumentException('Current page number must be less than or equal to the last page number.');
192
        }
193
    }
194
195
    protected function formatPageName(int $offset): string
196
    {
197
        return sprintf('page-%d', $this->currentPage + $offset);
198
    }
199
200
    protected function formatLink(int $offset): string
201
    {
202
        return Hyde::formatLink("{$this->formatPageName($offset)}.html");
203
    }
204
205
    protected function getRoute(int $offset): Route|string
206
    {
207
        return Routes::get("$this->routeBasename/{$this->formatPageName($offset)}") ?? Hyde::formatLink("$this->routeBasename/{$this->formatPageName($offset)}");
208
    }
209
210
    protected function firstPage(): int
211
    {
212
        return 1;
213
    }
214
}
215