Przepis na robienie paginacji w PHP, który raz poznany możemy zastosować w każdej sytuacji i używając jakiegokolwiek narzędzia. Do dzieła.

Krok pierwszy – złapać numer strony z query i rzutować do typu int:

$page = $_GET['p'] ?? 1;
$page = (int) $page;

Krok drugi – ustalić długość (ilość elementów per page) i offset według wzoru:

$length = 5;
$offset = ($page - 1) * $length;

Dla takiego wzoru ilość elementów per page dla strony pierwszej to 5 zaś offset to 0 (razy 5).

Druga strona posiada ilość per page 5 oraz offset 5 (razy 1).

SQL wygląda mniej-więcej tak:

SELECT (*)
FROM tablename
LIMIT 5
OFFSET 0

SELECT (*)
FROM tablename
LIMIT 5
OFFSET 5

W omawianym przykładzie łapiemy sobie jeszcze searchTerm oraz rekordy (tymi sqlami) i ilość wszystkich rekordów:

$searchTerm = $_GET['s'] ?? null;

    [$transactions, $count] = $this->transactionService->getUserTransactions(
      $length,
      $offset
    );

Ilość wszystkich rekordów zapewnia nam mniej-więcej taki SQL:

SELECT COUNT(*)
FROM tablename
WHERE searchterm
LIKE "%term%"

Oczywiście jeżeli chcemy się bawić w „SEARCH LIKE %” musimy w odpowiedniej metodzie zrobić escape na znaki takie jak „%” na przykład:

 public function getUserTransactions(int $length, int $offset)
  {
    $searchTerm = addcslashes($_GET['s'] ?? '', '%_');
//(...)

Chodzi generalnie o to, aby SQL nie mylił znaku „%” w nazwie poszukiwanego modelu z operatorem SQL.

Tak czy inaczej ostatnią stronę wyliczamy w ten sposób:

$lastPage = ceil($count / $length);

Ilość elementów podzielić na ilość elementów per page równa się ostatnia strona. Może równać się zero, może nie być ostatniej strony.

Mając to na uwadze możemy stworzyć zakres linków z numerami stron:

$lastPage = ceil($count / $length);
    $pages = $lastPage ? range(1, $lastPage) : [];

    $pageLinks = array_map(
      fn ($pageNum) => http_build_query([
        'p' => $pageNum,
        's' => $searchTerm
      ]),
      $pages
    );

Ważna uwaga – PHP to nie Python. To znaczy, że range od 1 do 10 obejmuje 10 (numer ostatniej strony na przykład). Żadnego +1 tam nie potrzebujemy!

We frameworku phpiggy, bo to jego omawiamy, koniec paginacji wygląda tak:

echo $this->view->render("index.php", [
      'transactions' => $transactions,
      'currentPage' => $page,
      'previousPageQuery' => http_build_query([
        'p' => $page - 1,
        's' => $searchTerm
      ]),
      'lastPage' => $lastPage,
      'nextPageQuery' => http_build_query([
        'p' => $page + 1,
        's' => $searchTerm
      ]),
      'pageLinks' => $pageLinks,
      'searchTerm' => $searchTerm
    ]);

Prawdę powiedziawszy – poznaliśmy patent na zrobienie paginacji w dowolnym frameworku (także własnym) a nawet bez niego.

Wszystko rozkłada się o zrozumienie kilku podstawowych konceptów i złożenie tego do kupy nie popełniając głupich błędów.