WebOrbiton
v1.0.0.1

StocketBase

121 lines · 4.5 KB
  1. <?php
  2. ​
  3. declare(strict_types=1);
  4. ​
  5. final class Pagination
  6. {
  7. public static function currentPage(): int
  8. {
  9. $page = (int) ($_GET['page'] ?? 1);
  10. return $page > 0 ? $page : 1;
  11. }
  12. ​
  13. public static function offset(int $page, int $perPage): int
  14. {
  15. return ($page - 1) * $perPage;
  16. }
  17. ​
  18. public static function totalPages(int $totalItems, int $perPage): int
  19. {
  20. if ($perPage <= 0) {
  21. return 1;
  22. }
  23. return max(1, (int) ceil($totalItems / $perPage));
  24. }
  25. ​
  26. public static function render(string $style, string $baseUrl, int $currentPage, int $totalPages, array $extraParams = [], string $containerId = ''): string
  27. {
  28. if ($totalPages <= 1) {
  29. return '';
  30. }
  31. ​
  32. return match ($style) {
  33. 'load_more' => self::renderLoadMore($currentPage, $totalPages, $containerId),
  34. 'infinite_scroll' => self::renderInfiniteScrollMarker($currentPage, $totalPages, $containerId),
  35. default => self::renderNumbered($baseUrl, $currentPage, $totalPages, $extraParams),
  36. };
  37. }
  38. ​
  39. private static function buildUrl(string $baseUrl, int $page, array $extraParams): string
  40. {
  41. $params = $extraParams;
  42. if ($page > 1) {
  43. $params['page'] = $page;
  44. }
  45. ​
  46. if (empty($params)) {
  47. return $baseUrl;
  48. }
  49. ​
  50. return $baseUrl . '?' . http_build_query($params);
  51. }
  52. ​
  53. private static function renderNumbered(string $baseUrl, int $currentPage, int $totalPages, array $extraParams): string
  54. {
  55. $html = '<nav class="pagination-numbered" aria-label="' . htmlspecialchars(Language::get('pagination_label', 'Pages'), ENT_QUOTES) . '">';
  56. ​
  57. if ($currentPage > 1) {
  58. $html .= '<a href="' . htmlspecialchars(self::buildUrl($baseUrl, $currentPage - 1, $extraParams)) . '" class="pagination-link pagination-prev">' . htmlspecialchars(Language::get('pagination_previous', 'Previous')) . '</a>';
  59. }
  60. ​
  61. foreach (self::pageWindow($currentPage, $totalPages) as $item) {
  62. if ($item === null) {
  63. $html .= '<span class="pagination-ellipsis">…</span>';
  64. continue;
  65. }
  66. $isCurrent = $item === $currentPage;
  67. $html .= '<a href="' . htmlspecialchars(self::buildUrl($baseUrl, $item, $extraParams)) . '" class="pagination-link' . ($isCurrent ? ' pagination-current' : '') . '"' . ($isCurrent ? ' aria-current="page"' : '') . '>' . $item . '</a>';
  68. }
  69. ​
  70. if ($currentPage < $totalPages) {
  71. $html .= '<a href="' . htmlspecialchars(self::buildUrl($baseUrl, $currentPage + 1, $extraParams)) . '" class="pagination-link pagination-next">' . htmlspecialchars(Language::get('pagination_next', 'Next')) . '</a>';
  72. }
  73. ​
  74. $html .= '</nav>';
  75. ​
  76. return $html;
  77. }
  78. ​
  79. private static function pageWindow(int $currentPage, int $totalPages): array
  80. {
  81. $window = 2;
  82. $pages = [];
  83. ​
  84. for ($i = 1; $i <= $totalPages; $i++) {
  85. if ($i === 1 || $i === $totalPages || ($i >= $currentPage - $window && $i <= $currentPage + $window)) {
  86. $pages[] = $i;
  87. } elseif (!empty($pages) && end($pages) !== null) {
  88. $pages[] = null;
  89. }
  90. }
  91. ​
  92. return $pages;
  93. }
  94. ​
  95. private static function renderLoadMore(int $currentPage, int $totalPages, string $containerId): string
  96. {
  97. if ($currentPage >= $totalPages) {
  98. return '';
  99. }
  100. ​
  101. $safeContainerId = htmlspecialchars($containerId);
  102. ​
  103. return '<div class="pagination-load-more" data-container="' . $safeContainerId . '" data-next-page="' . ($currentPage + 1) . '" data-total-pages="' . $totalPages . '">'
  104. . '<button type="button" class="unlock-btn pagination-load-more-btn" style="border:none;cursor:pointer;">' . htmlspecialchars(Language::get('pagination_load_more', 'Load more')) . '</button>'
  105. . '</div>';
  106. }
  107. ​
  108. private static function renderInfiniteScrollMarker(int $currentPage, int $totalPages, string $containerId): string
  109. {
  110. if ($currentPage >= $totalPages) {
  111. return '<div class="pagination-end">' . htmlspecialchars(Language::get('pagination_end', 'No more products')) . '</div>';
  112. }
  113. ​
  114. $safeContainerId = htmlspecialchars($containerId);
  115. ​
  116. return '<div class="pagination-infinite-marker" data-container="' . $safeContainerId . '" data-next-page="' . ($currentPage + 1) . '" data-total-pages="' . $totalPages . '"></div>';
  117. }
  118. }
  119. ​