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

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

  • md5

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

    Spritz 26 октября 2007 г. 6: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 = &quot;SELECT *
    FROM `table`
    LIMIT {$start}, {$nums}&quot;;





    [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 &#39; <a href=&quot;?page=1&quot;>начало</a> … <a href=&quot;?page=&#39; . ($page-1) . &#39;&quot;>←сюда</a> &#39;;
    }

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

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




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


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


    $nums = 10;

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

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

    $elements = $row[&#39;counter&#39;];

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


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


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

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

    $query = &quot;SELECT *
    FROM `table`
    LIMIT {$start}, {$nums}&quot;;
    $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 &#39; <a href=&quot;?page=1&quot;>начало</a> … <a href=&quot;?page=&#39; . ($page-1) . &#39;&quot;>←сюда</a> &#39;;
    }

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

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

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

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



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

    $nums = 10;



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


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





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


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

    adw/0
  • Lirck

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

    <?php
    $cost = $_POST[&#39;cost&#39;];
    $number = $_POST[&#39;number&#39;];
    $etaj = $_POST[&#39;etaj&#39;];
    $etajnost = $_POST[&#39;etajnost&#39;];
    $type = $_POST[&#39;type&#39;];
    $street = $_POST[&#39;street&#39;];


    if($street == &quot;x&quot;):
    $street1 = &quot;&quot;;
    else:
    $street1 = &quot; AND street = &#39;$street&#39;&quot;;
    endif;

    if($type == &quot;x&quot;):
    $type1 = &quot;&quot;;
    else:
    $type1 = &quot; AND type = &#39;$type&#39;&quot;;
    endif;

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

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

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

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

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

    @mysql_connect(&quot;localhost&quot;,&quot;root&quot;) or die (&quot;I&#39;m can&#39;t connect to MySQL&quot;);
    @mysql_select_db(stady) or die (&quot;I&#39;m can&#39;t connect to DB&quot;);
    $query = &quot;SELECT COUNT(*) AS `counter` FROM `apartament`&quot;;
    $sql = mysql_query($query) or die(mysql_error());
    $row = mysql_fetch_assoc($sql);
    $elements = $row[&#39;counter&#39;];
    $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 &#39;Колличество страниц:&#39;.&quot; $pages&quot;.&#39;<br />&#39;;

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

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

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





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

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

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

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

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

    endif;
    ?>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

    if (isset($_GET[&#39;page&#39;]) AND $_GET[&#39;page&#39;] != NULL)


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

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