ФорумПрограммированиеПыхнуть хотите?F.A.Q. → Постраничный вывод информации из БД (пагинатор)

Постраничный вывод информации из БД (пагинатор)

  • md5

    Сообщения: 11949 Репутация: N Группа: в ухо

    Spritz 26 октября 2007 г. 3:24

    [size=20]Постраничный вывод информации из БД (пагинатор)[/size]


    Итак, видел много таких штук и везде все по разному.
    Решил выложить и свой взгляд на это, чтобы всё было разобрано по шагам и очень доступно.

    [size=18]Предисловие[/size]

    И так, разбивка на страницы — это всего лишь немного логики, математики и LIMIT в SQL запросе.



    [size=18]Экшн[/size]

    [size=14]Для начала[/size]
    установим кол-во записей, выводимых на страницу.

    $nums = 10;



    [size=14]Затем[/size]
    мы определимся на какой странице находимся (в нашем случае мы будем передавать номер страницы GET'ом).


    if (isset($_GET['page']))
    {
    $page = intval($_GET['page']);
    }
    else
    {
    $page = 1;
    }


    [size=14]Посмотрим[/size]
    сколько всего у нас страниц, чтобы юзер не ввёл нам 1589 страницу из 13 возможных

    Для этого необходимо подсчитать кол-во элементов всего:



    $query = "SELECT COUNT(*) AS `counter`
    FROM `table`";
    $sql = mysql_query($query) or die(mysql_error());
    $row = mysql_fetch_assoc($sql);

    $elements = $row['counter'];



    [size=14]А уже[/size]
    кол-во страниц выясняется нехитрым методом деления всех элементов на кол-во на страницу и округляется в большую сторону.

    $pages = ceil($elements/$nums);




    Теперь проверим
    чтобы текущая страница не была меньше 1 и не больше последней страницы


    if ($page < 1)
    {
    $page = 1;
    }
    elseif ($page > $pages)
    {
    $page = $pages;
    }


    итак, в $page находится номер нашей страницы


    [size=14]Для[/size]
    лимита в нашем запросе, нам необходимо подстачитать первый оператор, который показывает с какой записи мы зачинаем делать выборку

    $start = ($page-1)*$nums;



    [size=14]Всё![/size]
    Запрос составлен:


    $query = "SELECT *
    FROM `table`
    LIMIT {$start}, {$nums}";





    [size=18]Листалка страниц[/size]


    [size=14]В нашем[/size]
    пагинаторе мы не будем выводить все страницы от 1 .. до 150 например, а будем выводить только соседние по отношению к текущей,
    например если у нас выбрана страница 5, то мы введем слева и справа от неё определённое кол-во страниц, допустим у нас это кол-во будет равно 6.

    $neighbours = 6;



    [size=14]Определяем[/size]
    крайнего левого и правого соседей


    $left_neighbour = $page - $neighbours;
    if ($left_neighbour < 1) $left_neighbour = 1;

    $right_neighbour = $page + $neighbours;
    if ($right_neighbour > $pages) $right_neighbour = $pages;




    [size=14]А как же[/size]
    нам вывести листалку?



    if ($page > 1)
    {
    print ' <a href="?page=1">начало</a> … <a href="?page=' . ($page-1) . '">←сюда</a> ';
    }

    for ($i=$left_neighbour; $i<=$right_neighbour; $i++)
    {
    if ($i != $page)
    {
    print ' <a href="?page=' . $i . '">' . $i . '</a> ';
    }
    else
    {
    // выбранная страница
    print ' <b>' . $i . '</b> ';
    }
    }

    if ($page < $pages)
    {
    print ' <a href="?page=' . ($page+1) . '">туда→</a><a href="?page=' . $pages . '">конец</a> … ';
    }




    [size=14]Вот[/size]
    мы и получили модную листалку как на яндексах, хабрах и т.д.


    [size=16]Соберём[/size]
    всё это в кучу!


    $nums = 10;

    if (isset($_GET['page']))
    {
    $page = intval($_GET['page']);
    }
    else
    {
    $page = 1;
    }

    $query = "SELECT COUNT(*) AS `counter`
    FROM `table`";
    $sql = mysql_query($query) or die(mysql_error());
    $row = mysql_fetch_assoc($sql);

    $elements = $row['counter'];

    $pages = ceil($elements/$nums);


    if ($page < 1)
    {
    $page = 1;
    }
    elseif ($page > $pages)
    {
    $page = $pages;
    }


    $start = ($page-1)*$nums;

    // когда у нас в таблице нет записей
    if ($start < 0) $start = 0;

    $query = "SELECT *
    FROM `table`
    LIMIT {$start}, {$nums}";
    $sql = mysql_query($query) or die(mysql_error());

    while ($row = mysql_fetch_assoc($sql))
    {
    // здесь выводим наши записи из базы
    }




    // далее нам надо прицепить листалку

    $neighbours = 6;
    $left_neighbour = $page - $neighbours;
    if ($left_neighbour < 1) $left_neighbour = 1;

    $right_neighbour = $page + $neighbours;
    if ($right_neighbour > $pages) $right_neighbour = $pages;

    if ($page > 1)
    {
    print ' <a href="?page=1">начало</a> … <a href="?page=' . ($page-1) . '">←сюда</a> ';
    }

    for ($i=$left_neighbour; $i<=$right_neighbour; $i++)
    {
    if ($i != $page)
    {
    print ' <a href="?page=' . $i . '">' . $i . '</a> ';
    }
    else
    {
    // выбранная страница
    print ' <b>' . $i . '</b> ';
    }
    }

    if ($page < $pages)
    {
    print ' <a href="?page=' . ($page+1) . '">туда→</a> … <a href="?page=' . $pages . '">конец</a> ';
    }
    1. pager.gif (761)
    все умрут, а я изумруд
  • adw0rd

    Сообщения: 22905 Репутация: N Группа: в ухо

    Spritz 12 декабря 2007 г. 17:21, спустя 47 дней 14 часов 57 минут



    [size=14]Для начала[/size]
    установим кол-во записей, выводимых на страницу.

    $nums = 10;



    [size=14]Затем[/size]
    мы определимся на какой странице находимся (в нашем случае мы будем передавать номер страницы GET'ом).


    if (isset($_GET['page']))
    {
    $page = intval($_GET['page']);
    }
    else
    {
    $page = 1;
    }





    а что получится если http://example.com/?page=
    мы получим $page = 0 , далее ты это предусмотрел, но всетки логичнее будет в самом начале проверить:


    if (isset($_GET['page']) AND $_GET['page'] != NULL)
    {
    $page = intval($_GET['page']);
    }
    else
    {
    $page = 1;
    }

    adw/0
  • Lirck

    Сообщения: 1658 Репутация: N Группа: Джедаи

    Spritz 17 февраля 2008 г. 3:40, спустя 66 дней 10 часов 18 минут

    Я немного модифицировал, чтобы листалка не скакала то в право, то влево:

    if ($page> 1)
    {
    print ' <a href="?page=1">Начало</a> … <a href="?page=' . ($page-1) . '">Назад</a> ';
    }

    if ($page == 1)
    {
    print ' Начало … Назад ';
    }

    for ($i=$left_neighbour; $i<=$right_neighbour; $i++)
    {
    if ($i != $page)
    {
    print '<a href="?page=' . $i . '">' . $i . '</a> ';
    }
    else
    {
    print ' <b>' . $i . '</b> ';
    }
    }

    if ($page < $pages)
    {
    print '<a href="?page=' . ($page+1) . '">Вперед</a> … <a href="?page=' . $pages . '">Конец</a>';
    }

    if ($page == $pages)
    {
    print ' Вперед … Конец ';
    }
  • Neolink

    Сообщения: 4 Репутация: N Группа: Кто попало

    Spritz 17 февраля 2008 г. 5:52, спустя 2 часа 12 минут 34 секунды

    Доброго вам времени.
    Подкинули ссылку с другого сайта на эту статью. Попробовал применить данный совет к моему скрипту. И сразу же столкунулся с непреодолимым чувством, образовавшимся в моей голове, и чуть позже, распространившимся, по всему телу, я понял меня колбасит…
    Вопрос собственна говоря такой:
    Есть форма в которую воодиться информация в последствии по этой информаии отбираеються данные из БД и конечно выводяться на кинескоп. В этом месте я дописал ваш код. Данные отбираються нормально по всем параметрам введенным в форму. Строк БД выводиться тоже стока скока указал в LIMIT однако при переходе по ссылке на вторую страницу все отказываеться работать пишет что ошибка данных для запроса к БД. Полагаю, что данные введенные в форму не передаються на вторую страницу. Кто-нибудь может с этим помочь?
  • disc

    Сообщения: 843 Репутация: N Группа: Джедаи

    Spritz 17 февраля 2008 г. 6:04, спустя 11 минут 39 секунд

    Neolink, не стоит курить траву или употреблять ЛСД при изучении языков программирования. Помочь вам могут ваши окружающие товарищи и если ситуация уже запущено, то лучше обратиться к специалистам :)

    Если по существу, то свои слова необходимо подкреплять кодом, чтоб мы начинающие телепаты могли на 100% уверены в своих догадках.
  • Neolink

    Сообщения: 4 Репутация: N Группа: Кто попало

    Spritz 17 февраля 2008 г. 6:22, спустя 18 минут 29 секунд

    ОК
    Код правда не маленький… сразу всем спасибо кто дочитает его до конца.

    <form action="output.php" method="post">
    <input type="hidden" name="seenform" value="y">
    <table border="1p" summary="">
    <tr>
    <td>Колличество комнат</td>
    <td>
    <select name="number" size="5">
    <option value="1" selected>Одна.
    </option>
    </select>
    </td>
    </tr>
    <tr>
    <td>Стоимость</td>
    <td>
    <table>
    <tr>
    <td>
    <input name="variant" value="mr" type="radio" checked />Менее<br />
    <input name="variant" value="br" type="radio" />Более
    </td>
    <td>
    <select name="cost" size="7">
    <option value="" selected>Не имеет значения
    </option>
    </select>
    </td>
    </tr>
    </table>
    </td>
    </tr>
    <tr>
    <td>Тип</td>
    <td>
    <select name="type" size="4">
    <option value="x" selected>Не имеет значения
    </option>
    </select>
    </td>
    </tr>
    <tr>
    <td>Этаж</td>
    <td>
    <select name="etaj">
    <option value="x" selected>Не имеет значения
    </option>
    </select>
    </td>
    </tr>
    <tr>
    <td>Этажность
    </td>
    <td>
    <select name="etajnost" size="1" maxlength="5">
    <option value="x" selected>Не имеет значения
    </option>
    </td>
    </tr>
    <tr>
    <td>Улица</td>
    <td>
    <select name="street">
    <option value="x" selected>Не имеет значения
    </option>
    </select>
    </td>
    <tr>
    <tr>
    <td>
    </td>
    <td>
    <input type="submit" value="Искать." />
    </td>
    </tr>
    </table>
    </form>


    Конечно я его сократил дамы не утомлять ваши очи, но сократил я его только в тех местах где был повторяющийся код (не выводить же сюда несколько сотен улиц города).
    Знаю что его можно усовершенствовать в разных моментах но это меня пока не интересует.

    Ну а вот файл экшена

    <?php
    $cost = $_POST['cost'];
    $number = $_POST['number'];
    $etaj = $_POST['etaj'];
    $etajnost = $_POST['etajnost'];
    $type = $_POST['type'];
    $street = $_POST['street'];


    if($street == "x"):
    $street1 = "";
    else:
    $street1 = " AND street = '$street'";
    endif;

    if($type == "x"):
    $type1 = "";
    else:
    $type1 = " AND type = '$type'";
    endif;

    if($etaj == "x"):
    $etaj1 = "";
    else:
    $etaj1 = " AND etaj = $etaj";
    endif;

    if($etajnost == "x"):
    $etajnost1 = "";
    else:
    $etajnost1 = " AND etajnost = $etajnost";
    endif;

    if($variant == "mr"):
    $op = "<";
    else:
    $op = ">";
    endif;

    if(isset($cost)):
    $cost1 = "";
    else:
    $cost1 = " AND cost = $cost";
    endif;

    /*Данные для листалки*/
    $nums = 10;
    if (isset($_GET['page']))
    {$page = intval($_GET['page']);}
    else
    {$page = 1;}
    $neighbours = 6;
    /*Конец данных для листалки*/

    @mysql_connect("localhost","root") or die ("I'm can't connect to MySQL");
    @mysql_select_db(stady) or die ("I'm can't connect to DB");
    $query = "SELECT COUNT(*) AS `counter` FROM `apartament`";
    $sql = mysql_query($query) or die(mysql_error());
    $row = mysql_fetch_assoc($sql);
    $elements = $row['counter'];
    $pages = ceil($elements/$nums);
    //СОСЕДИ
    $left_neighbour = $page - $neighbours;
    if ($left_neighbour < 1) $left_neighbour = 1;
    $right_neighbour = $page + $neighbours;
    if ($right_neighbour > $pages) $right_neighbour = $pages;
    //КОНЕЦ СОСЕДЯМ
    if ($page < 1){$page = 1;} elseif ($page > $pages){$page = $pages;} //ПРОВЕРКА НА БОЛЬШЕ МЕНЬШЕ ЧЕМ ЕСТЬ
    $start = ($page-1)*$nums;
    echo 'Колличество страниц:'." $pages".'<br />';

    echo "'$number' '$cost1' '$etaj1' '$etajnost1' '$type1' '$street1' '<br />'";
    $query = "SELECT * FROM apartament WHERE number = '$number' $cost1 $etaj1 $etajnost1 $street1 $type1 $street1 LIMIT $start, $nums";
    echo $query;

    $result = mysql_query($query);
    if(mysql_num_rows($result) == 0):
    echo "По вашему запросу ничего не найденно. Попробуйте расширить запрос.";
    else:

    echo "<table><tr><th>Контакт</th><th>Цена</th><th>Кол. ком.</th><th>Этаж/ Этажность</th><th>Улица</th><th>Тип</th><th>Состояние</th><th>Нал. телефона</th><th>Примечание</th></tr>";
    while(list($name, $phone, $email, $cost, $number, $etaj, $etajnost, $street, $type, $condition, $telephone, $description, $begin, $end) = mysql_fetch_row($result)):
    echo "<tr>
    <td>$name<br />$phone<br />$email</td><td>$cost тыс.руб.</td><td>$number</td><td>$etaj/$etajnost</td><td>$street</td><td>$type</td><td>$condition</td><td>$telephone</td><td>$description</td>
    </tr>
    ";
    endwhile;
    echo "</table>";





    if ($page> 1)
    {
    print ' <a href="?page=1">Начало</a> … <a href="?page=' . ($page-
    1) . '">Назад</a> ';
    }

    if ($page == 1)
    {
    print ' Начало … Назад ';
    }

    for ($i=$left_neighbour; $i<=$right_neighbour; $i++)
    {
    if ($i != $page)
    {
    print '<a href="?page=' . $i . '">' . $i . '</a> ';
    }
    else
    {
    print ' <b>' . $i . '</b> ';
    }
    }

    if ($page < $pages)
    {
    print '<a href="?page=' . ($page+1) . '">Вперед</
    a> … <a href="?page=' . $pages . '">Конец</a>';
    }

    if ($page == $pages)
    {
    print ' Вперед … Конец ';
    }

    endif;
    ?>


    Сразу говорю, вариант с расположением на одной странице формы и её экшена у меня тоже есть но там при переходе по ссылке на вторую страницу перекидывает опять на форму. Однако следует отметить, что после того как перекинет при нажатии на кнопку "Искать." выходишь именно на правильную страницу. Вообщем одни загадки.
    Спасибо.
  • disc

    Сообщения: 843 Репутация: N Группа: Джедаи

    Spritz 17 февраля 2008 г. 6:52, спустя 29 минут 55 секунд

    Про "дамы" в начале ты отжог :) да и сама запись твоих условий "IF" тоже порадовала, PHP3 :) хотя давно уже пора на 5ке писать. Читайте свеживе книги за 2006-2007 года, а не старые книги Котерова.
  • Neolink

    Сообщения: 4 Репутация: N Группа: Кто попало

    Spritz 17 февраля 2008 г. 7:07, спустя 15 минут

    Да, тока не в этом дело.
    Проблема собственна следующая если кто заметил.
    При переходе на вторую страницу данные введенные в форму не передаються на эту самую страницу. Как вариант вижу обозначить эти переменные как глобальные. Но как понимаю это не бзопасно. Так кто-нибудь поможет?
  • disc

    Сообщения: 843 Репутация: N Группа: Джедаи

    Spritz 17 февраля 2008 г. 7:11, спустя 3 минуты 54 секунды

    у тебя номер страницы передается в $_GET['page'], ты это никак не используешь.
  • AlexB

    Сообщения: 4290 Репутация: N Группа: в ухо

    Spritz 17 февраля 2008 г. 7:36, спустя 24 минуты 59 секунд

    При переходе на вторую страницу данные введенные в форму не передаються на эту самую страницу.
    Правильно, а с какого перепугу они будут передаваться, если ты их никак туда не передаешь? Иди в мануал, сначала читай чем GET отличается от POST, потом читай про сессии.
  • Neolink

    Сообщения: 4 Репутация: N Группа: Кто попало

    Spritz 17 февраля 2008 г. 10:10, спустя 2 часа 34 минуты 5 секунд

    Уникальные ответы. Спасибо. Для disk отвечаю использую смотри внимательней, к нему ни каких притензий нет.
    Знаю чем get отличаеться от post и что? Потому вас и спрашиваю, что сделать что бы работало.
  • AlexB

    Сообщения: 4290 Репутация: N Группа: в ухо

    Spritz 17 февраля 2008 г. 10:17, спустя 7 минут 19 секунд


    Знаю чем get отличаеться от post и что?
    Если это знаешь, то должен понять, что в GET запросе никаким образом не могут оказаться данные из предыдущего POST запроса.


    Потому вас и спрашиваю, что сделать что бы работало.
    Я тебе ответил. Повторяю еще раз - СЕССИИ.

    Другой вариант, переделать пагинатор так, чтоб он методом пост вместе со страницей каждый раз отправлял данные заново.
  • disc

    Сообщения: 843 Репутация: N Группа: Джедаи

    Spritz 17 февраля 2008 г. 12:00, спустя 1 час 42 минуты 29 секунд

    Neolink, я но понимаю какие ты можешь предъявлять претензии людям, которые пытаются наставить тебя на истинный путь. Тебе говорят советы как тебе надо поступить, а ты пытаешься их оспорить. Если ты такой умный то зачем задаешь "тупые" вопросы?
  • ervlen

    Сообщения: 208 Репутация: N Группа: Кто попало

    Spritz 29 сентября 2008 г. 1:59, спустя 224 дня 12 часов 59 минут

    Измените в разделе статьи эту статью )). А то я там скопировал, а ссылки на листалке не прописаны. А здесь норм вроде.
  • Trej Gun

    Сообщения: 5299 Репутация: N Группа: в ухо

    Spritz 29 сентября 2008 г. 2:48, спустя 48 минут 22 секунды

    if (isset($_GET['page']) AND $_GET['page'] != NULL)


    а че можно писать AND и OR??? я всегда писал && и || ткните носов в ман может там еще и побитовые операции можно)))

Пожалуйста, авторизуйтесь, чтобы написать комментарий!