WebOrbiton
v1.0.0.0

StocketBase

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