Russian (Pусский) translation by Elen (you can also view the original English article)
Я вспоминаю, когда много лет назад, когда я только начинал писать код PHP и MySQL, я был весьма рад, когда впервые моя информация из базы данных отобразилась в браузере.
Я был на триумфальной высоте перед теми, у кого не было больших знаний в сфере баз данных и программирования, и кто видел те строки таблицы, появляющимися на экране в результате написанного мною кода (ну хорошо, я просто скопировал пример из книги - не будем вдаваться в подробности). Возможно, я не вполне понимал всех тонкостей этой работы, но этот первый успех стимулировал меня к работе над большими и лучшими проектами.
Хотя мой уровень в отношении баз данных не таков, как был раньше, сейчас он значительно богаче,
со времени моего первого знакомства с PHP и MySQL, меня пленила
мысль делать вещи более простыми и легкими в использовании.
Как разработчик я постоянно сталкиваюсь с одной проблемой: принятие большого количества информации и попытка легко усвоить ее. Является ли это список клиентов крупной компании или личный mp3-каталог, вынужденность сидеть и смотреть на строку над строкой, строку над строкой разных данных может быть весьма скучным занятием
и даже более - вы можете разочароваться. Что может сделать хороший разработчик? Разбить на страницы!
1. Разбивка на страницы
Разбиение на страницы - это по существу процесс принятия набора результатов и распределение
их по страницам, чтоб их было легче читать.

Ещё раньше я размышлял, если бы у меня было 500 строчек информации, которую нужно отобразить, это было бы
не только головной болью для того, кто попытается все это прочитать, но и большинство браузеров
потратили бы целую вечность (т.е. более чем пять секунд) на отображение этой информации.
Чтобы решить эту проблему я мог бы написать разные инструкции SQL, чтобы вытащить фрагменты данных, и если бы у меня
было хорошее настроение, я бы даже сделал пару кнопок, «далее» и «предыдущая».
Через некоторое время, мне нужно было внести этот код в очень похожий проект и настроить
его, чтобы подогнать под старый вариант. Быстро. И как каждый хороший разработчик знает, лень рождает изобретательность
или что-то в этом роде. Поэтому, однажды, я сел и решил придумать простой,
гибкий и легкий в использовании класс PHP, который автоматически бы делал грязную работу
вместо меня.
Несколько слов обо мне и классах PHP. Я не волшебник в сфере объектно-ориентированного программирования. На самом деле, я практически
никогда не использую подобные вещи. Но после прочтения некоторых примеров ООП и учебных материалов, а также
простых примеров проб и ошибок, я решил сделать решительный поворот, и знаете, что?
Он идеально работает для разбивки на страницы. Код, который я здесь использую, написан в PHP 4, но
он работает и в PHP 5.
2. База данных
Вам нужно любить MySQL. Не хочу обидеть другие системы баз данных, но
для меня, все что мне нужно - это MySQL. Одной из прекрасных особенностью MySQL является то, что они дают вам
некоторые бесплатные примеры баз данных, с которыми вы можете поиграться: http://dev.mysql.com/doc/#sampledb.
В моем случае я буду использовать всемирную базу данных (архив ~ 90 k), которая содержит
свыше 4000 записей, с которыми можно поработать, но красота PHP-скрипта, который мы будем создавать, в том,
что его можна использовать для любой базы данных. Теперь, думаю, мы все можем согласиться, что если мы решили
не разбивать наши результаты, в итоге мы получим очень длинный и громоздкий
список результатов, как примерно показано ниже:

(кликните, чтобы получить изображение в полном размере, оно невероятно длинное, ~ 338k)
Потому давайте пойдем дальше, разбивая наши данные в легко обрабатываемые байты, как показано ниже:

Красиво, не так ли? После того, как вы ввели клас разбивки на страницы в ваш код, вы можете
быстро и просто превратить огромный набор данных в страницы, по которым можно легко перемещаться
с помощью всего нескольких строк кода. Это на самом деле так.
3. Пагинатор
Данный пример будет состоять с двух скриптов, многоразового класса paginator и файла index, который будет выводить элементы таблицы и элементы управления.
Paginator.class.php
Класс рaginator будет иметь только два метода и конструктор, мы будем строить их постепенно, объясняя каждый шаг по мере того, как мы движемся вперед.
<?php class Paginator { private $_conn; private $_limit; private $_page; private $_query; private $_total; }
Это определение только устанавливает необходимые члены-переменные пагинатора. Так как это вспомогательный класс и он разработан только для пагинации, он будет полагаться на валидное подключение к серверу MySQL и на уже определенный запрос, который мы добавим к параметрам, необходимым для разбивки результатов. Мы начнем с метода конструктор.
<?php public function __construct( $conn, $query ) { $this->_conn = $conn; $this->_query = $query; $rs= $this->_conn->query( $this->_query ); $this->_total = $rs->num_rows; }
Довольно просто, не так ли? Этот метод только устанавливает соединение базы данных объекта и необходимый запрос, после чего он вычисляет общее количество строк, полученных этим запросом без каких-либо ограничений или пропусков параметров. Эта сумма необходима для создания ссылок для пагинатора.
Обратите внимание, что для простоты мы не выполняем проверку ошибок или любую другую проверку данных параметров, но в реальности эта проверка необходима.
Получение результатов
Теперь давайте создадим метод, который, собственно, будет выполнять пагинацию данных и возвращать результаты.
<?php public function getData( $limit = 10, $page = 1 ) { $this->_limit = $limit; $this->_page = $page; if ( $this->_limit == 'all' ) { $query = $this->_query; } else { $query = $this->_query . " LIMIT " . ( ( $this->_page - 1 ) * $this->_limit ) . ", $this->_limit"; } $rs = $this->_conn->query( $query ); while ( $row = $rs->fetch_assoc() ) { $results[] = $row; } $result = new stdClass(); $result->page = $this->_page; $result->limit = $this->_limit; $result->total = $this->_total; $result->data = $results; return $result; }
Давайте сейчас проанализируем этот шаг: сначала мы установили лимит и параметры страницы, которые по умолчанию установлены на 10 и 1 соответственно. Далее мы проверяем, запрашивает ли пользователь заданное число строк или все из них и, основываясь на этом и на параметрах страницы, мы устанавливаем параметр LIMIT
этого запроса. Значение "-1" берется с учётом того, что мы начинаем нумерацию страницы с 1, но не с 0.
После этого мы просто оцениваем запрос и получаем результаты, наконец, мы создаем новый объект результатов, который содержит лимит, страницу и общие параметры выполненного запроса, а также данные для каждой из полученных строк.
Отображение пагинальных ссылок
Теперь давайте напишем метод, который используется для получения пагинальных ссылок.
<?php public function createLinks( $links, $list_class ) { if ( $this->_limit == 'all' ) { return ''; } $last = ceil( $this->_total / $this->_limit ); $start = ( ( $this->_page - $links ) > 0 ) ? $this->_page - $links : 1; $end = ( ( $this->_page + $links ) < $last ) ? $this->_page + $links : $last; $html = '<ul class="' . $list_class . '">'; $class = ( $this->_page == 1 ) ? "disabled" : ""; $html .= '<li class="' . $class . '"><a href="?limit=' . $this->_limit . '&page=' . ( $this->_page - 1 ) . '">«</a></li>'; if ( $start > 1 ) { $html .= '<li><a href="?limit=' . $this->_limit . '&page=1">1</a></li>'; $html .= '<li class="disabled"><span>...</span></li>'; } for ( $i = $start ; $i <= $end; $i++ ) { $class = ( $this->_page == $i ) ? "active" : ""; $html .= '<li class="' . $class . '"><a href="?limit=' . $this->_limit . '&page=' . $i . '">' . $i . '</a></li>'; } if ( $end < $last ) { $html .= '<li class="disabled"><span>...</span></li>'; $html .= '<li><a href="?limit=' . $this->_limit . '&page=' . $last . '">' . $last . '</a></li>'; } $class = ( $this->_page == $last ) ? "disabled" : ""; $html .= '<li class="' . $class . '"><a href="?limit=' . $this->_limit . '&page=' . ( $this->_page + 1 ) . '">»</a></li>'; $html .= '</ul>'; return $html; }
Это довольно длинный метод, примерно на 34 строки кода, потому давайте объясним, что как происходит в этом методе.
- Сначала мы оцениваем, требует ли пользователь заданное количество ссылок или все из них, в противном случае, мы просто возвращаем пустую строку, так как пагинация не требуется.
- После этого мы вычисляем последнюю страницу на основе общего количества доступных строк и элементов, необходимых для каждой страницы.
- После этого мы берем параметры ссылок, которые отображают количество ссылок, которые нужно разместить вверху и внизу текущей страницы и вычисляем, когда создать начальную и конечную ссылку.
- Теперь мы создаем открывающий тег для списка и устанавливаем для него параметр класса и добавляем ссылку "предыдущая страница". Обратите внимание, что для этой ссылки мы проверяем, является ли текущая страница первой, и если да, то мы устанавливаем для ссылки свойство "недоступен".
- На данный момент мы отображаем ссылку на первой странице и символ многоточия в случае, если начальная ссылка не является первой.
- Затем мы добавляем ссылки ниже и выше текущей страницы, исходя из ранее вычисленных начальных и конечных параметров. На каждом шагу мы снова оцениваем текущую страницу, отображаемую страницу ссылки, и соответственно устанавливаем активный класс.
- После этого мы отображаем другой символ многоточия и ссылку на последнюю страницу в случае, если конечная ссылка не есть последняя.
- Наконец мы показываем ссылку «Следующая страница» и устанавливаем отключенное состояние, когда пользователь просматривает последнюю страницу. Закройте список и вернитесь на сгенерированную строку HTML.
Это все, что касается Paginator.class. Конечно, мы могли бы добавить сеттеры и геттеры для подключения к базе данных, ограничения, страницы, запрос и полные параметры, но для простоты мы сохраним его таким как есть.
4. Index.php
Теперь мы создадим файл, отвечающий за использование класса Paginator и отображение данных, поэтому сначала позвольте мне показать вам базовый HTML.
<!DOCTYPE html> <head> <title>PHP Pagination</title> <link rel="stylesheet" href="css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="col-md-10 col-md-offset-1"> <h1>PHP Pagination</h1> <table class="table table-striped table-condensed table-bordered table-rounded"> <thead> <tr> <th>City</th> <th width="20%">Country</th> <th width="20%">Continent</th> <th width="25%">Region</th> </tr> </thead> <tbody></tbody> </table> </div> </div> </body> </html>
Довольно просто, этот файл отображает только таблицу, которую мы заполним требуемой с баз данных информацией. Обратите внимание, что для этого примера я использую bootstrap для базового стиля страницы.
Использование пагинатора
<?php for( $i = 0; $i < count( $results->data ); $i++ ) : ?> <tr> <td><?php echo $results->data[$i]['Name']; ?></td> <td><?php echo $results->data[$i]['Country']; ?></td> <td><?php echo $results->data[$i]['Continent']; ?></td> <td><?php echo $results->data[$i]['Region']; ?></td> </tr> <?php endfor; ?>
Теперь, чтобы воспользоваться классом пагинатора, добавьте следующий РНР-код в верхней части документа.
<?php require_once 'Paginator.class.php'; $conn = new mysqli( '127.0.0.1', 'root', 'root', 'world' ); $limit = ( isset( $_GET['limit'] ) ) ? $_GET['limit'] : 25; $page = ( isset( $_GET['page'] ) ) ? $_GET['page'] : 1; $links = ( isset( $_GET['links'] ) ) ? $_GET['links'] : 7; $query = "SELECT City.Name, City.CountryCode, Country.Code, Country.Name AS Country, Country.Continent, Country.Region FROM City, Country WHERE City.CountryCode = Country.Code"; $Paginator = new Paginator( $conn, $query ); $results = $Paginator->getData( $page, $limit ); ?>
Этот скрипт достаточно прост. Мы просто вызвали класс пагинатор, обратите внимание, что этот код предполагает, что этот файл находится в той же папке, что и файл index.php
. Если это не так, вы должны соответствующим образом обновить путь.
Затем мы создаем соединение с нашей базой данных с помощью библиотеки MySQLi, извлекаем параметры пагинатора из запроса GET и устанавливаем запрос, так как это не статья на MySQL или что-либо другое, во что я не буду вдаваться в подробности.
Наконец, мы создали объект Paginator и извлекли результаты для текущей страницы.
Отображение результатов
Теперь, чтобы отобразить полученные результаты, добавьте следующий код в тело таблицы.
<?php for( $i = 0; $i < count( $results->data ); $i++ ) : ?> <tr> <td><?php echo $results->data[$i]['Name']; ?></td> <td><?php echo $results->data[$i]['Country']; ?></td> <td><?php echo $results->data[$i]['Continent']; ?></td> <td><?php echo $results->data[$i]['Region']; ?></td> </tr> <?php endfor; ?>
Здесь мы просто повторяем атрибут данных результатов, содержащих записи городов, и создавая строку таблицы для каждого из них.
Ссылки пагинации
Теперь, чтобы отобразить ссылки пагинатора, добавьте следующий код ниже таблицы.
<?php echo $Paginator->createLinks( $links, 'pagination pagination-sm' ); ?>
Для метода Paginator createLinks мы передаем полученный параметр links и класс css для ссылок пагинации, использованных на bootstrap. Вот результат созданной страницы.

Заключение
Этот материал должен обеспечить вас всем, что вам нужно, чтобы осуществить пагинацию в вашем приложении.
Пожалуйста, не стесняйтесь, оставляйте ниже ваши вопросы, комментарии или обобщенный отзыв!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post