Обратная пагинация [Reversed pagination]

Выкладываем свои наработки
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

[updated]
Документация и исходный код перемещены на github:
https://github.com/DeusModus/yii-ext-re ... pagination

Скриншоты.
Первая страница(она же site/index, она же site/page/5):
Изображение
Последняя страница(всегда site/page/1):
Изображение
Последний раз редактировалось DeusModus 2011.08.21, 18:59, всего редактировалось 3 раза.
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение rak »

ээ а чем навигация хабра отличается от навигации того же rmcreative?
Вроде просто desc выборка, а завтра и там и там сегодняшний контент окажется на 2+ странице
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

У меня в голове почему-то навигация хабра по-другому выглядела. Присмотрелся и правда. Тогда только баш остается.
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Получилось как-то так:

Код: Выделить всё

<?php
class Pagination extends CPagination
{
    private $_currentPage;

    /**
     * @param boolean $recalculate whether to recalculate the current page based on the page size and item count.
     * @return integer the zero-based index of the current page. Defaults to 0.
     */
    public function getCurrentPage($recalculate = true)
    {
        if ($this->_currentPage === null || $recalculate) {
            if (isset($_GET[$this->pageVar])) {
                $this->_currentPage = (int)$_GET[$this->pageVar] - 1;
                if ($this->validateCurrentPage) {
                    $pageCount = $this->getPageCount();
                    if ($this->_currentPage >= $pageCount){
                        $this->_currentPage = $pageCount - 1;
                    }
                }
                if ($this->_currentPage < 0){
                    $this->_currentPage = 0;
                }
            }
            else{
                $this->_currentPage = $this->getPageCount()-1;
            }
        }
        $reversePageNumber = $this->getPageCount() - $this->_currentPage - 1;
        return $reversePageNumber;
    }

    /**
     * Creates the URL suitable for pagination.
     * This method is mainly called by pagers when creating URLs used to
     * perform pagination. The default implementation is to call
     * the controller's createUrl method with the page information.
     * You may override this method if your URL scheme is not the same as
     * the one supported by the controller's createUrl method.
     * @param CController $controller the controller that will create the actual URL
     * @param integer $page the page that the URL should point to. This is a zero-based index.
     * @return string the created URL
     */
    public function createPageUrl($controller,$page)
    {
        $params=$this->params===null ? $_GET : $this->params;
        if($page>=0) // page 0 is the default
            $params[$this->pageVar]=$page+1;
        else{
            unset($params[$this->pageVar]);
        }
        return $controller->createUrl($this->route,$params);
    }
}

 

Код: Выделить всё

<?php
class LinkPager extends CLinkPager {
    /**
     * Creates the page buttons.
     * @return array a list of page buttons (in HTML code).
     */
    protected function createPageButtons()
    {
        if(($pageCount=$this->getPageCount())<=1)
            return array();

        list($beginPage,$endPage)=$this->getPageRange();
        $currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()
        $buttons=array();

        // first page
        $buttons[]=$this->createPageButton($this->firstPageLabel,$pageCount,self::CSS_FIRST_PAGE,$currentPage<=0,false);

        // prev page

        if(($page=$pageCount-$currentPage)<=$pageCount){
            $page=$pageCount-1;
        }
        $buttons[]=$this->createPageButton($this->prevPageLabel,$page,self::CSS_PREVIOUS_PAGE,$currentPage<=0,false);

        // internal pages
        for($i=$endPage;$i>=$beginPage;--$i){
            $buttons[]=$this->createPageButton($i+1,$i,self::CSS_INTERNAL_PAGE,false,$i==$pageCount-1-$currentPage);
        }

        // next page

        if(($page=$pageCount-$currentPage-2)<=0){
            $page=0;
        }
        $buttons[]=$this->createPageButton($this->nextPageLabel,$page,self::CSS_NEXT_PAGE,$currentPage>=$pageCount-1,false);

        // last page
        $buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,self::CSS_LAST_PAGE,$currentPage>=$pageCount-1,false);

        return $buttons;
    }
}

 
Изменения не очень большие. Остается баг с первой страницей (на нее ведет ссыла ?page=9 вместо просто слеша), думаю пофиксю попозже.
Если у кого-нибудь есть более приятные решения - милости прошу :)
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение Ekstazi »

А к чему все это ? Ставьте order правильный при выборке данных.
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Вероятно вы не поняли задачу.
Чем мне поможет order в этой ситуации?
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение rak »

Ekstazi писал(а):А к чему все это ? Ставьте order правильный при выборке данных.
не, тут фишка в том, что если статья добавлена на 60 страницу, то она всегда на 60 и останется, а не переместится на 61,62 итп
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение Ekstazi »

И в чем проблема ? если не переместится, то делаем сортировку правильную. (данные то не добавляются иначе как бы оно на месте стояло).
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение rak »

в том то и дело, что данные добавляются, но результаты остаются на той же странице, где и были. В общем это отлично демонстрирует http://bash.org.ru/
Мы находимся на главной, а на самом деле это(на данный момент) 615 страница, завтра те же цитаты, что и сейчас, тоже будут находиться на 615 странице, а главной будет уже 620. Т.е. используется, конечно, сортировка desc, но самое важное, как представлены урлы страницы и пагинация.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение Ekstazi »

То есть вы хотите чтоб на первой странице всегда оставалось неопределенное число новостей ? А на самой последней - фиксированое.
P.S.: за баш.орг такого не отметил.
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Что значит неопределенное? На 1 странице именно что всегда одно и тоже. Это в блоге сэма все страницы смещаются время от времени, потому что старые материалы вытесняют новые и завтра на первой может быть что-то иное чем вчера.
Сегодня - 3 2 1
Завтра - 4 3 2 1

Пс:.все баги поправил как у эвм появлюсь обновлю код.
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение Ekstazi »

Не нет, не одна и то же. Вчера на первой было 29 цитат. Сегодня может уже и 39 быть. А вообще, по моим примерным подсчетам у них на странице должно быть 59. Выходит что на первой странице всегда между 1 и 59 цитатами, то есть часть цитат гуляет межу 1-й и 2-й страницей.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение rak »

ну да, получается на главной будет все время переменное кол-во, это конечно не очень хорошо
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Чтобы не путаться, давайте считать первой страницей ту, которая в виджете пагинации первая.
Выбрали цитаты, отсортированные по дате с лимитом 10.
Время: xx:xx , цитат 7
< 1 >
Время: xx:xx, цитат 10
< 1 >
Время: xx:xx, цитат 11
< 2 1 >
Время: xx:xx, цитат 15
< 2 1 >

Пока для главной (2) не наберется 10 цитат(тоесть всего не будет 20) ничего никуда не сдвинется.
Если вы имели ввиду эту "плавучесть", что пока материал набирается на главной может быть от 1 до limit материалов, то да. Но ничего плохого в этом не вижу. Можно обновлять главную по достижение какого-то вменяемого количества материалов.

Контроллер:

Код: Выделить всё

    public function actionIndex()
    {
        $criteria = new CDbCriteria();
        $criteria->order = 'approve_date DESC';
        $criteria->addColumnCondition(array('enabled' => '1',));

        $count = Quote::model()->count($criteria);
        
        $pages = new Pagination($count);
        $pages->pageSize = $this->quotesPerPage;
        $pages->applyLimit($criteria);

        $quotes = Quote::model()->findAll($criteria);

        $this->pageTitle = Yii::t('quote', 'Last');

        $this->render('index', array(
                                    'quotes' => $quotes,
                                    'pages' => $pages
                               ));
    }
 
Переопределенный CPagination с перегруженными методами (обновленный и кажется без ошибок прошлого поста):

Код: Выделить всё

<?php
class Pagination extends CPagination
{
    private $_currentPage;

    public function getCurrentPage($recalculate = true)
    {
        if(Yii::app()->controller->useReverseNavigation===false){
            return parent::getCurrentPage($recalculate);
        }
        
        if ($this->_currentPage === null || $recalculate) {
            if (isset($_GET[$this->pageVar])) {
                $this->_currentPage = (int)$_GET[$this->pageVar] - 1;
                if ($this->validateCurrentPage) {
                    $pageCount = $this->getPageCount();
                    if ($this->_currentPage >= $pageCount){
                        $this->_currentPage = $pageCount - 1;
                    }
                }
                if ($this->_currentPage < 0){
                    $this->_currentPage = 0;
                }
            }
            else{
                $this->_currentPage = $this->getPageCount()-1;
            }
        }
        $reversePageNumber = $this->getPageCount() - $this->_currentPage - 1;
        return $reversePageNumber;
    }

    public function createPageUrl($controller,$page)
    {
        if(Yii::app()->controller->useReverseNavigation===false){
            return parent::createPageUrl($controller,$page);
        }

        $params=$this->params===null ? $_GET : $this->params;
        if($page>=0 && $page!=$this->getPageCount()-1) // page 0 is the default
            $params[$this->pageVar]=$page+1;
        else{
            unset($params[$this->pageVar]);
        }
        return $controller->createUrl($this->route,$params);
    }
}
 
Перегруженный LinkPager:

Код: Выделить всё

<?php
class LinkPager extends CLinkPager {
    /**
     * Creates the page buttons.
     * @return array a list of page buttons (in HTML code).
     */
    protected function createPageButtons()
    {
        if(Yii::app()->controller->useReverseNavigation===false){
            return parent::createPageButtons();
        }

        if(($pageCount=$this->getPageCount())<=1)
            return array();

        list($beginPage,$endPage)=$this->getPageRange();
        $currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()
        $buttons=array();

        // first page
        $buttons[]=$this->createPageButton($this->firstPageLabel,$pageCount-1,self::CSS_FIRST_PAGE,$currentPage<=0,false);

        // prev page

        if(($page=$pageCount-$currentPage)>=$pageCount){
            $page=$pageCount-1;
        }
        $buttons[]=$this->createPageButton($this->prevPageLabel,$page,self::CSS_PREVIOUS_PAGE,$currentPage<=0,false);

        // internal pages
        for($i=$endPage;$i>=$beginPage;--$i){
            $buttons[]=$this->createPageButton($i+1,$i,self::CSS_INTERNAL_PAGE,false,$i==$pageCount-1-$currentPage);
        }

        // next page

        if(($page=$pageCount-$currentPage-2)<=0){
            $page=0;
        }
        $buttons[]=$this->createPageButton($this->nextPageLabel,$page,self::CSS_NEXT_PAGE,$currentPage>=$pageCount-1,false);

        // last page
        $buttons[]=$this->createPageButton($this->lastPageLabel,0,self::CSS_LAST_PAGE,$currentPage>=$pageCount-1,false);

        return $buttons;
    }
}
 
Чтобы всё это корректно работало добавьте в базовый контроллер публичный член:

Код: Выделить всё

class Controller extends CController
{
    <...>
    public $useReverseNavigation = false;
    <...>
}
  
И в случае необходимости построения обратной навигации установите его значение в true в нужном вам контроллере или в базовом.
Скриншоты.
Первая страница(она же site/index, она же site/page/5):
Изображение
Последняя страница(всегда site/page/1):
Изображение
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение Ekstazi »

Спасибо вам за интересную идею с пагинацией, да, с такими объяснениями понятно что и как.
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Ekstazi писал(а):Спасибо вам за интересную идею с пагинацией, да, с такими объяснениями понятно что и как.
Переместите в viewforum.php?f=9 . Первый пост обновил, так что вполне сойдет за авторский код.
В случае необходимости могу оформить как компоненты.
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Обратная пагинация [Reversed pagination]

Сообщение samdark »

Может сразу в расширение оформить и в отдельную репку на GitHub?
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

Можно и так.
Тогда я все еще раз проверю, напишу нормальные комментарии и завтра выложу.
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Аватара пользователя
DeusModus
Сообщения: 95
Зарегистрирован: 2011.01.05, 23:07
Откуда: спб

Re: Обратная пагинация [Reversed pagination]

Сообщение DeusModus »

up
Как и обещал, репозиторий - https://github.com/DeusModus/yii-ext-re ... pagination .
Установка, использования, примеры и код.

PS: http://www.yiiframework.com/ext/create/ не дал создать расширение:
Sorry, you are too new to add an extension to the repository. Please try posting it in our forum first.
Не хочу флудить на форуме, может можно как-то обойти ограничение?
Правильное действие,в основе своей простоты.Если жизнь кажется сложной,вы что-то делаете не так.
Аватара пользователя
Koduc
Сообщения: 140
Зарегистрирован: 2011.02.15, 18:56

Re: Обратная пагинация [Reversed pagination]

Сообщение Koduc »

Попытался использовать ваше решение - что-то у меня "не взлетело".
Быстрее оказалось закреативить своё решение, чем искать ошибку :)
http://www.yiiframework.ru/forum/viewto ... f=9&t=5244
Разработка на Yii: monoray.ru
Открытое бесплатное решение для создания сайтов по аренде/продаже недвижимости: Open Real Estate
Ответить