PHP: Постраничная навигация

Сегодня я решил рассказать о том как можно легко организовать постраничную навигацию в PHP.
Пожалуй каждый разработчик веб приложений сталкивался с задачей постраничного вывода контента на страницах приложения. В целом алгоритм данной задачи всегда примерно одинаков.

1) Определяем текущую страницу и сколько записей мы выводим на странице.
2) Определяем сколько записей у нас всего.
3) Делаем выборку по записям текущей страницы.
4) Выводим ссылки на другие страницы.

Если преобразовать данные строки в код PHP, то выглядеть это будет примерно так:

//Определяем текущую страницу
$page = !empty($_REQUEST['page']) && is_numeric($_REQUEST['page']) && $_REQUEST['page'] > 0 ? $_REQUEST['page'] : 1;
//Определяем сколько записей выводить на странице
$onPage = 10;

//Формируем условия выборки из базы
$where = 'WHERE field1 = "'.strip_tags($_REQUEST['filter1']).'" AND field2 = "'.strip_tags($_REQUEST['filter2']).'"';

//Узнаем сколько всего записей удовлетворяет нашей выборке
$count = mysql_query('SELECT COUNT(*) as c FROM table '.$where);
$count = mysql_fetch_assoc($count);
$count = $count['c'];
//Получаем строки выбранной страницы
$rows = mysql_query('SELECT * FROM table '.$where.' LIMIT '.(($page - 1) * $onPage).', '.$onPage);
while($row = mysql_fetch_assoc($rows)) {
   //Вывод строк
}
//Определим сколько страниц всего
$pagesCount = ($count % $onPage == 0 ? $count / $onPage : ((int)($count / $onPage)) + 1;
//Выводим список страниц
for($i = 1; $i <= $pagesCount; ++$i) {
   echo $i == $page ? $i : '<a href="/linkToScript.php?page='.$i.'&filter1='.strip_tags($_REQUEST['filter1']).'&filter2='.strip_tags($_REQUEST['filter2']).'">'.$i.'</a>';
}

Данная реализация вполне имеет место быть, однако есть в ней один момент, который часто «портит всю малину». Этот момент — необходимость генерировать запрос получения количества всех записей, удовлетворяющих текущим фильтрам (три строчки с $count). Весь подвох заключается в том, что строку условий $where не всегда так легко получить и подставить в запрос «SELECT COUNT». В данном случае приходиться включать смекалку и выкручиваться любыми доступными методами.
Я хочу рассказать Вам об одной прекрасной конструкции языка mysql, которая позволяет решить данную проблему и практически не приведет к изменению примера выше. Речь идет о ключевом слове SQL_CALC_FOUND_ROWS который можно использовать в запросе SELECT, если в нем присутствует ключевое слово LIMIT. Данное ключевое слово говорит Mysql сохранить число общего число записей, которое было выбрано запросом до применения ограничения LIMIT (если Вы не в курсе, то ограничение LIMIT срабатывает после выборки всех строк запроса). Для получения данного сохраненного числа так же используется запрос, который сработает гораздо быстрей, чем запрос SELECT COUNT.
В конечном итоге наш код будет модифицирован следующим образом:

//Определяем текущую страницу
$page = !empty($_REQUEST['page']) && is_numeric($_REQUEST['page']) && $_REQUEST['page'] > 0 ? $_REQUEST['page'] : 1;
//Определяем сколько записей выводить на странице
$onPage = 10;

//Формируем условия выборки из базы
$where = 'WHERE field1 = "'.strip_tags($_REQUEST['filter1']).'" AND field2 = "'.strip_tags($_REQUEST['filter2']).'"';

//Получаем строки выбранной страницы
$rows = mysql_query('SELECT SQL_CALC_FOUND_ROWS * FROM table '.$where.' LIMIT '.(($page - 1) * $onPage).', '.$onPage);

//Получаем общее число записей, полученное в последнем запросе до применения ограничения LIMIT
$count = mysql_query('SELECT FOUND_ROWS() as c');
$count = mysql_fetch_assoc($count);
$count = $count['c'];

while($row = mysql_fetch_assoc($rows)) {
   //Вывод строк
}
//Определим сколько страниц всего
$pagesCount = ($count % $onPage == 0 ? $count / $onPage : ((int)($count / $onPage)) + 1;
//Выводим список страниц
for($i = 1; $i <= $pagesCount; ++$i) {
   echo $i == $page ? $i : '<a href="/linkToScript.php?page='.$i.'&filter1='.strip_tags($_REQUEST['filter1']).'&filter2='.strip_tags($_REQUEST['filter2']).'">'.$i.'</a>';
}

Как видно, изменения минимальны. Однако удобство данного подхода на лицо 🙂

Запись опубликована в рубрике PHP с метками , , , , , , , . Добавьте в закладки постоянную ссылку.