Всем нам с детства знакомы эти ссылки – хотя бы по страницам документации PHP:
Мы находимся на странице описания функции array_slice, а вверху страницы видим ссылки на соседние темы: array_shift слева (предыдущая) и array_splice справа (следующая). Как организовать такую фигню для произвольного списка (например, для просмотра списка товаров)?
Очевидным кажется примерно такое решение (1). Исходим из того, что данные хранятся в БД Mysql, а первичный ключ (поле id) – возрастающие числа (auto_increment). Идентификатор текущего элемента (страницы, на которой находимся) мы знаем (current_id = 3), делаем в процессе генерации страницы ещё один запрос к базе: select * from `tovar` where `id` = (current_id – 1) – и находим предыдущий элемент. Таким же запросом, но с `id` = current_id + 1, находим следующий элемент. И рисуем ссылки вида href="static/tovar.php?id=2".
Но если позже мы удалим товар с id=4, то по вычисленной методом 1 ссылке попадём на пустую страницу (404). Отсюда возникает Решение 2: делаем запрос не "напрямую" к вычисленному в PHP элементу, а по "относительному пути": select * from `tovar` where `id` < current_id limit 1 (и такой же запрос, но с `id` > current_id, – для следующего элемента).
Метод Решения 2 работает практически идеально, пока мы не захотим изменить сортировку начального списка. Например, удобно бывает просматривать товары, упорядоченные по наименованию (а вовсе не по абстрактным числам-идентификаторам). Хотя... что мешает написать в запросе where `name` < 'current_name'? Видимо то, что в базе может быть два товара с абсолютно одинаковым наименованием, а отличия могут храниться, например, в поле "спецификация".
Пользователь может просматривать список результатов поиска по всей базе товаров, или по определённой рубрике, отсортированный по наименованиям или по дате изменения... В принципе, в любом случае можно сформировать sql-запрос с учётом всех входящих условий отбора и сортировки. Но зачем? Почему мы должны заново конструировать сложный запрос при получении отдельных элементов (next & previous) списка, если мы один раз его уже сконструировали – при получении всего начального списка?
При формировании страницы со списком элементов (товаров) мы имеем доступ ко всему списку. Можно сделать из этого списка подходящий (уменьшенный) массив с числовыми ключами, содержащий идентификаторы страницы и (например) заголовки. Ну, или, для простоты, два отдельных массива:
Массивы эти хранить, пожалуй, можно только в сессии, например, в свойствах $_SESSION['list_ids'] и $_SESSION['list_names']. Тогда ссылку на соседний элемент можно будет формировать примерно так:
Недостаток постоянного хранения списка в сессии очевиден: пока мы листаем товары, хозяин может удалить какой-то товар (или перенести в другую рубрику), и мы попадём на страницу 404, так как наш хранимый список сам по себе не обновляется.
Отсюда вытекает «пуленепробиваемый» способ получения соседних элементов – повторное обращение на странице элемента к функционалу, формирующему начальный список. Казалось бы, это сложнее, чем «лишний» запрос к базе. Да, наверное, немного сложнее (больше работы) – для компьютера. Но зато вдвое меньше работы для программиста! Мы ведь не добавляем новые функции, а повторно используем готовые.
Допустим, мы формируем видимый список товаров с помощью вызова $catalog->get($params). Тогда при листании товаров нужно будет перед выводом каждой страницы получать тот же список с теми же параметрами. Откуда же их взять, «те же параметры», если мы уже ушли со страницы списка? Изначально они брались из УРЛ, значит, всё-таки надо где-то хранить УРЛ страницы списка. То есть уже не сам список, а как бы «ключ» к нему.
В УРЛ списка у нас есть всё необходимое, включая строку поиска: "tovar_list.php?category=4&q=люминивые". С одной стороны, удобно, а с другой – придётся запускать весь движок, чтобы начать с разбора УРЛ и закончить получением списка. Поэтому, для обеспечения «короткого вызова» вида $catalog->get($params) прямо где-нибудь в шаблоне, лучше всё-таки хранить в сессии конкретно вот эти $params, а не УРЛ. В общем, схема получается такая: