1

Тема: Digg-style pagination class для CodeIgniter (php5)

Как-то искал я библиотеку для нормальной разбивки по страницам для CI.

Было 2 критерия:
1) Нумерация - page/, page/2, page/3, ...
2) Digg-style. Например у нас 231 страница, а вы находитесь на 8, пагинация будет выглядеть так:
1 2 ... 5 6 7 8 9 10 11 ... 231

К сожалению ничего похожего найти не удалось и было принято решение писать библиотеку самому, расширив стандартый класс Pagination.

Так что представляю вам библиотеку Digg-style Pagination v 1.0 для CodeIgniter (полностью совместима с оригинальной).

В контроллере используем так:

public function page($page = 1)
{
    $this->load->library('pagination');
    $this->load->model('articles_model');

    $module = $this->uri->segment(1);
    $method = $this->uri->segment(2);
    $page = $this->uri->segment(3);
        
    if($method == 'page' & empty($page)) show_404();

    if(!is_numeric($page) && !empty($page)){
        show_404();
    } elseif(!isset($page) || empty($page)){
        $page = max(1, (int)$this->uri->segment(3));
    }

    $limit = 5;
    $totalrows = $this->articles_model->count();

    $offset = ($page - 1) * $limit;
    if ($totalrows <= $offset) show_404();

    $config['base_url'] = base_url().$module.'/page/';
    $config['total_rows'] = $totalrows;
    $config['per_page'] = $limit;
    $config['padding'] = 2;
    $config['num_links'] = 5;
    $config['first_link'] = '‹';
    $config['last_link'] = '›';
    $config['next_link'] = 'следующая »';
    $config['prev_link'] = '« предыдущая';
    $config['first_tag_close'] = '';
    $config['last_tag_open'] = '';
    $config['cur_tag_open'] = '&nbsp;<span class="current">';
    $config['cur_tag_close'] = '</span>';
        
    //$config['num_links'] = ceil ($config['total_rows']/$config['per_page']);
    $config['full_tag_open'] = '';
    $config['full_tag_close'] = '';
    $config['uri_segment'] = '3';

    $this->pagination->initialize($config); 

    $data['articles'] = $this->articles_model->get_articles($limit, $offset);
        
    $this->load->view('articles_index_tpl', $data);
}

В модели:

public function get_articles($limit=5, $offset=0)
{
    $query = $this->db
        ->select('id, name, annonce')
        ->from('articles')
        ->where('publish', 1)
        ->order_by('date','desc')
        ->limit($limit, $offset)
        ->get();

    if ($query->num_rows() > 0){
        $rows = $query->result();
        $query->free_result();
        return $rows;
    } else {
        return FALSE;
    }
}

public function count()
{
    $query = $this->db->select('COUNT(*) AS total')->from('articles')->where('publish', 1)->get();
    return $query->row()->total;
}

В отображении:

<div class="pagination">
    <?php echo trim($this->pagination->create_links()); ?>
</div>

Ну и стили (меняем по вкусу:)):

div.pagination {
    font:normal 11px Arial, Helvetica, sans-serif;
    padding:3px 0;
    margin:3px 0;
}

div.pagination a,
div.pagination strong,
div.pagination span.disabled,
div.pagination span.current {
    padding:2px 5px;
    margin-right:4px;
    text-decoration:none;
}

div.pagination a {
    border:1px solid #CCC;
    color:#1c2939;
}

div.pagination a:hover,
div.pagination a:active {
    border:1px solid #1c2939;
    color:#1c2939;
}

div.pagination strong,
div.pagination span.current {
    border:1px solid #1c2939;
    font-weight:bold;
    background-color:#1c2939;
    color:#FFF;
}

div.pagination span.disabled  {
    border:1px solid #CCC;
    color:#CCC;
}

PS: Файл MY_Pagination.phps переименуйте в MY_Pagination.php и скопируйте в папку:
application/libraries/

Отредактировано Developer (12.10.2009 11:51:06)

Post's attachments

Attachment icon MY_Pagination.phps 8.13 kb, 734 downloads since 2009-10-07 

Thumbs up +1 Thumbs down

2

Re: Digg-style pagination class для CodeIgniter (php5)

Как минимум неверно будет работать подсчет количества статей, а соответственно и строка с пейджингом, т.к. у Вас не проверяется значение publish при подсчете данных.

Вообще, вместо своих запросов можно использовать встроенный AR, тогда метод count будет выглядеть:

public function count(){
    $this->db->where('publish', 1);
    return $this->db->count_all_results('articles');
}

Также непонятно зачем нужна такая длинная проверка есть ли данные:

if ($query->num_rows() > 0){
        $rows = $query->result();
        $query->free_result();
        return $rows;
    } else {
        return FALSE;
    }

Да и зачем пытаться воспрепятствовать автоматическому "заслешеванию" данных в запросе. Вообще, проще переписать этот метод модели:

public function get_articles($limit=5, $offset=0){
    return $this->db
        ->select('id, name, annonce')
        ->where('publish', 1)
        ->get('articles', $limit, $offset)
        ->result_array();
}

А для проверки в контроллере добавить просто:

// Вызов сделать повыше, чтобы удалить все ненужное
$data['articles'] = $this->articles_model->get_articles($limit, $offset);

// Вот проверка, ее вполне хватит для всего пейджинга
if (sizeof($data['articles']) === 0) show_404();

Саму либу не смотрел, но уже метод контроллера "page" настораживает... А если кроме статей будет еще 50 контроллеров, везде делать page? Может проще в новой библиотеке сделать проверку на параметр с page (смотри документацию по URI в сторону метода uri_to_assoc() ) и обратно наоборот
assoc_to_uri() с добавлением page...

Thumbs up Thumbs down

3

Re: Digg-style pagination class для CodeIgniter (php5)

aleXoid пишет:

Как минимум неверно будет работать подсчет количества статей, а соответственно и строка с пейджингом, т.к. у Вас не проверяется значение publish при подсчете данных.

Верное замечание, поправил пост.

aleXoid пишет:

Также непонятно зачем нужна такая длинная проверка есть ли данные:

if ($query->num_rows() > 0){
        $rows = $query->result();
        $query->free_result();
        return $rows;
    } else {
        return FALSE;
    }

У меня в проектах используется модульная архитектура HMVC 5 и widgets, поэтому нелишним будет использовать $query->free_result(); для очистки от ненужных ресурсов.

aleXoid пишет:

Да и зачем пытаться воспрепятствовать автоматическому "заслешеванию" данных в запросе. Вообще, проще переписать этот метод модели:

public function get_articles($limit=5, $offset=0){
    return $this->db
        ->select('id, name, annonce')
        ->where('publish', 1)
        ->get('articles', $limit, $offset)
        ->result_array();
}

Дело в том что запрос у меня гораздо сложнее. SELECT не заслешиваю, потому что там стоит DATE_FORMAT(date, '%d/%m/%Y') AS adate, а смысла заслешивать единицу честно говоря не вижу. На всякий случай убрал FALSE, вдруг новички вместо константы переменную будут использовать...

Вы возвращаете array, а мне проще работать с object array.

aleXoid пишет:

А для проверки в контроллере добавить просто:

// Вот проверка, ее вполне хватит для всего пейджинга
if (sizeof($data['articles']) === 0) show_404();

Разумно, но вы не учли 1 момент:
/articles/
/articles/page/
будут показывать одну и ту же страницу, что не хорошо для поисковиков, поэтому у меня в условии стоит вывод 404 для страницы /articles/page/.

aleXoid пишет:

Саму либу не смотрел, но уже метод контроллера "page" настораживает... А если кроме статей будет еще 50 контроллеров, везде делать page? Может проще в новой библиотеке сделать проверку на параметр с page (смотри документацию по URI в сторону метода uri_to_assoc() ) и обратно наоборот
assoc_to_uri() с добавлением page...

Я ставил своей целью сделать библиотеку расширяющую стандартный pagination под конкретные условия и полностью совместимую с ним.

Thumbs up Thumbs down