Пагинация на PHP с применением ООП и Composer.
@phpproglib
Для удобного перемещения по записям почти на каждом сайте есть пагинация. Если коротко, это постраничный вывод некоторого числа постов или новостей. В этой статье мы научимся делать простую пагинацию, используя ООП и Composer.
Приготовления
Для автозагрузки наших классов мы будем использовать Composer. У кого его нет, советуем скачать и в будущем пользоваться им постоянно. Composer позволяет устанавливать дополнительные библиотеки для проекта и определять собственные пространства имён в файле composer.json.
composer.json
{
"autoload": {
"psr-4": {
"Engine\\": "src/"
}
}
}
Создаём файл composer.json и в директиве autoload указываем стандарт автозагрузки классов psr-4, который описывает спецификацию для автозагрузки классов на основе путей файлов. Мы указали, что нашим пространством будет папка Engine, которая находится в папке src. Поскольку обратный слеш экранирует кавычки, мы должны поставить два слеша. После всего в терминале прописываем команду composer dump-autoload, в результате чего у нас появится папка vendor, где в будущем будут храниться все сторонние библиотеки и файл autoload.php.
configs.php
Правилом хорошего тона является создание гибких классов, которые не заставят посторонних программистов лезть в него, поэтому все настройки подключения к базе данных мы вынесем в отдельный файл configs.php, чья единственная функция - вернуть массив настроек.
return array (
'host' => '127.0.0.1',
'dbname' => 'pagination',
'username' => 'root',
'password' => 'root'
);
Каждый, кто будет использовать наш класс, должен только указать свои настройки подключения к базе, а наш класс подключится сам.
Работа с базой данных
Database.php
В классе Database мы будем использовать PDO для подготовленных запросов и напишем только конструктор и два метода - метод для получения числа всех записей в базе и метод вывода записей по лимиту.
Указываем пространство имён, по которому будем загружать наш класс.
<?php namespace Engine;
Поскольку мы используем пространство имён, мы можем загрузить встроенный класс PDO.
use PDO;
class Database
{
Создаём приватную переменную $pdo, которая будет хранить подключение к базе.
private $pdo;
Переменная settings будет массивом, который будет хранить настройки подключения.
private $settings = [];
В этой переменной будут храниться результаты выполнения наших методов.
private $statement;
Отсюда мы будем считать записи.
private $from;
И выводить определённое число записей.
private $to;
Конструктор принимает массив настроек, ключами которого являются те самые ключи массива из файла configs.php, созданного ранее, и возвращает подключение, если оно удалось.
public function __construct(array $settings)
{
$this->settings = $settings;
try {
$this->pdo = new PDO('mysql:host=' . $this->settings['host']. ';dbname=' . $this->settings['dbname'], $this->settings['username'], $this->settings['password']);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
} catch (\PDOException $e) {
exit($e->getMessage());
}
return $this->pdo;
}
Метод getDataCount() возвращает число записей из базы данных и сохраняет их в ключ total.
public function getDataCount()
{
$this->statement = $this->pdo->query('SELECT COUNT(*) as total FROM posts');
return $this->statement->fetch();
}
С методом getLimitData() немного сложнее: он принимает два параметра - откуда считать посты и по сколько. Дальше мы делаем подготовленный запрос к базе и связываем параметры с помощью метода PDO bindParam, куда на всякий случай передаём константу PDO::PARAM_INT, чтобы точно передать целое число. Наконец, возвращаем массив с данными.
public function getLimitData($from, $to)
{
$this->from = $from;
$this->to = $to;
$this->statement = $this->pdo->prepare('SELECT * FROM posts LIMIT :from,:to');
$this->statement->bindParam(':from', $this->from, PDO::PARAM_INT);
$this->statement->bindParam(':to', $this->to, PDO::PARAM_INT);
$this->statement->execute();
return $this->statement->fetchAll(PDO::FETCH_OBJ);
}
Отображение данных
index.php
Чтобы можно было загрузить класс Database по его неймспейсу, надо подключить файл autoload.php.
<?php require_once 'vendor/autoload.php';
Загружаем класс Database.
use Engine\Database;
Создаём переменную, куда загружаем массив из файла configs.php.
$settings = require_once 'configs.php';
Передаём эти настройки в объект класса Database.
$some_object = new Database($settings);
Вызываем метод getDataCount() и сохраняем в переменной pages.
$pages = $some_object->geteDataCount()['total'];
В этой переменной храним значение числа записей на одну страницу (например, 5).
$per_page = 5;
Чтобы узнать количество страниц, нужно поделить количество записей в базе на число записей на страницу и округлить с помощью ceil() в большую сторону, чтобы не потерять последние записи.
$number_of_pages = ceil($pages / $per_page);
Проверяем, на какой странице находимся: если не существует GET-параметра page, то мы на первой странице. Если параметр GET существует, то берём его значение и присваиваем переменной $page для дальнейшего использования в запросе к базе.
$page = !isset($_GET['page']) ? 1 : $_GET['page'];
Тут мы получаем каждую первую запись следующей страницы, то есть
(1 - 1) * 10 = 0
(2 - 1) * 10 = 10
(3 - 1) * 10 = 20
(4 - 1) * 10 = 30, где первая цифра (1, 2, 3, 4) - это номер страницы,
а результат (0, 10, 20, 30) - ID первой записи на каждой новой странице.
$first_result_on_every_page = ($page - 1) * $per_page;
Вызываем метод getLimitData() и получаем число записей на страницу.
$posts = $some_object->getLimitData($first_result_on_every_page, $per_page);
Простой цикл, где выводим названия и контент статей. Используем двойные кавычки в echo, чтобы избежать конкатенации.
foreach ($posts as $post) {
echo "<h1>$post->title</h1>";
echo "<h4>$post->body</h4>";
}
Наконец, выводим пагинацию. В атрибут href передаём GET параметр page, значение которого будет использовано для определения необходимых записей на страницу.
for ($page = 1; $page <= $number_of_pages; $page++) {
echo "<a href='?page=$page'>$page</a>" . ' ';
}

Собственно, такой мы получили результат. В качестве интересной возможности вы можете предложить пользователям самим выбирать, какое количество записей будет выводиться на странице. Так делает популярный сайт stackoverflow. Для этого с помощью HTML создайте option или кнопки, значения которых будете сохранять в переменной $page (напомню, что до этого мы там сохранили число 5). На этом логика работы над пагинацией заканчивается, вам остаётся сделать её вывод красивым.