Issues (121)

src/Utils/Pagination.php (1 issue)

1
<?php
2
3
namespace Jidaikobo\Kontiki\Utils;
4
5
/**
6
 * Pagination class to handle pagination logic for SQL queries.
7
 *
8
 * This class provides methods to calculate LIMIT and OFFSET for pagination, as well as helper
9
 * methods to determine the existence of next and previous pages.
10
 */
11
class Pagination
12
{
13
    /** @var int Current page number */
14
    protected int $currentPage;
15
16
    /** @var int Number of items per page */
17
    protected int $itemsPerPage;
18
19
    /** @var int Total number of items in the dataset */
20
    protected int $totalItems;
21
22
    /** @var int Total number of pages calculated based on total items and items per page */
23
    protected int $totalPages;
24
25
    /**
26
     * Constructor to initialize pagination settings.
27
     *
28
     * @param int $currentPage The current page number.
29
     * @param int $itemsPerPage The number of items to display per page.
30
     */
31
    public function __construct(int $currentPage = 1, int $itemsPerPage = 10)
32
    {
33
        $this->currentPage = max(1, $currentPage); // Ensure current page is at least 1
34
        $this->itemsPerPage = max(1, $itemsPerPage); // Ensure items per page is at least 1
35
    }
36
37
    /**
38
     * Set the total number of items and calculate total pages.
39
     *
40
     * @param int $totalItems The total number of items.
41
     */
42
    public function setTotalItems(int $totalItems): void
43
    {
44
        $this->totalItems = $totalItems;
45
        $this->totalPages = (int) ceil($totalItems / $this->itemsPerPage);
46
    }
47
48
    /**
49
     * Get the offset for SQL queries.
50
     *
51
     * @return int The calculated offset based on the current page and items per page.
52
     */
53
    public function getOffset(): int
54
    {
55
        return ($this->currentPage - 1) * $this->itemsPerPage;
56
    }
57
58
    /**
59
     * Get the limit for SQL queries.
60
     *
61
     * @return int The limit, or number of items per page.
62
     */
63
    public function getLimit(): int
64
    {
65
        return $this->itemsPerPage;
66
    }
67
68
    public function getTotalItems(): int
69
    {
70
        return $this->totalItems;
71
    }
72
73
    /**
74
     * Check if there is a next page available.
75
     *
76
     * @return bool True if there is a next page, otherwise false.
77
     */
78
    public function hasNextPage(): bool
79
    {
80
        return $this->currentPage < $this->totalPages;
81
    }
82
83
    /**
84
     * Check if there is a previous page available.
85
     *
86
     * @return bool True if there is a previous page, otherwise false.
87
     */
88
    public function hasPreviousPage(): bool
89
    {
90
        return $this->currentPage > 1;
91
    }
92
93
    /**
94
     * Generate pagination links for navigation.
95
     *
96
     * @return array An array of page links with each link containing the page number and its current status.
97
     */
98
    public function getPageLinks(): array
99
    {
100
        $links = [];
101
        for ($i = 1; $i <= $this->totalPages; $i++) {
102
            $links[] = [
103
                'page' => $i,
104
                'isCurrent' => $i === $this->currentPage,
105
            ];
106
        }
107
        return $links;
108
    }
109
110
    /**
111
     * Get the current page number.
112
     *
113
     * @return int The current page number.
114
     */
115
    public function getCurrentPage(): int
116
    {
117
        return $this->currentPage;
118
    }
119
120
    /**
121
     * Render pagination links as HTML.
122
     *
123
     * @param string $baseUrl The base URL for pagination links.
124
     * @param bool $isAjax Whether to add an AJAX-specific class to links.
125
     * @return string The generated pagination HTML.
126
     */
127
    public function render(string $baseUrl, bool $isAjax = false): string
128
    {
129
        $pageLinks = $this->getPageLinks();
130
        $ajaxClass = $isAjax ? ' page-link-ajax' : '';
131
132
        if (count($pageLinks) === 1) {
133
            return '';
134
        }
135
136
        $html = '<nav aria-label="Page navigation">';
137
        $html .= '<ul class="pagination">';
138
        $html .= $this->renderPreviousLink($baseUrl, $ajaxClass);
139
        $html .= $this->renderPageLinks($baseUrl, $ajaxClass);
140
        $html .= $this->renderNextLink($baseUrl, $ajaxClass);
141
        $html .= '</ul>';
142
        $html .= '</nav>';
143
144
        return $html;
145
    }
146
147
    private function renderPreviousLink(string $baseUrl, string $ajaxClass): string
148
    {
149
        if ($this->hasPreviousPage()) {
150
            $previousPage = $this->currentPage - 1;
151
            $html = '';
152
            $html .= '<li class="page-item">';
153
            $html .= '<a class="page-link' . $ajaxClass . '" href="' . $baseUrl . '?paged=' . $previousPage . '" aria-label="Previous" data-page="' . $previousPage . '">';
154
            $html .= '<span aria-hidden="true">&laquo;</span>';
155
            $html .= '</a></li>';
156
            return $html;
157
        }
158
        return '<li class="page-item disabled"><span class="page-link">&laquo;</span></li>';
159
    }
160
161
    private function renderNextLink(string $baseUrl, string $ajaxClass): string
162
    {
163
        if ($this->hasNextPage()) {
164
            $html = '';
165
            $nextPage = $this->currentPage + 1;
0 ignored issues
show
The assignment to $nextPage is dead and can be removed.
Loading history...
166
            $nextPage = $this->currentPage + 1;
167
            $html .= '<li class="page-item">';
168
            $html .= '<a class="page-link' . $ajaxClass . '" href="' . $baseUrl . '?paged=' . $nextPage . '" aria-label="Next" data-page="' . $nextPage . '">';
169
            $html .= '<span aria-hidden="true">&raquo;</span>';
170
            $html .= '</a></li>';
171
            return $html;
172
        }
173
        return '<li class="page-item disabled"><span class="page-link">&raquo;</span></li>';
174
    }
175
176
    private function renderPageLinks(string $baseUrl, string $ajaxClass): string
177
    {
178
        $html = '';
179
        foreach ($this->getPageLinks() as $link) {
180
            $eachPage = $link['page'];
181
            $activeClass = $link['isCurrent'] ? ' active' : '';
182
            $ariaCurrent = $link['isCurrent'] ? ' aria-current="page"' : '';
183
            $html .= '<li class="page-item' . $activeClass . '">';
184
            $html .= '<a class="page-link' . $ajaxClass . '" href="' . $baseUrl . '?paged=' . $eachPage . '"' . $ariaCurrent . ' data-page="' . $eachPage . '">' . $eachPage . '</a>';
185
            $html .= '</li>';
186
        }
187
        return $html;
188
    }
189
}
190