Как сделать пагинацию (отстраничиватель)?

A1x

Новичок
ну например когда выбираешь данные сфинксом листать приходится сфинкс, а модель потом просто выбирает данные для страницы по списку айди
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Что значит листать сфинкс?
Листать по определению можно только данные. А данные — это модель. Модель не обязана быть «данными из базы». Модель — это любые данные, объединенные по смыслу в единую сущность. В твоем случае, сфинкс — это тоже модель. И более того, поиск по критерию, даже по текстовому, должен быть именно у модели.
 

A1x

Новичок
Листать сфинкс - я имел в виду что мы передаем limit и offset сфинксу а не в SQL запрос, опять же из сфинкса получаем total count

ну я вынес сфинкс в сервис. Просто хотел сказать что часто пишется код пагинации с железным предположением что все будет браться из SQL
а иногда это не так.

вот пример моего кода из контроллера (на кохане)
PHP:
protected function _loadListing() {

        $this->_limit = Pager::getNumPerPage(Pager::MAIN);
        $this->_offset = Pager::getOffset($this->_pageNum, $this->_limit);

        $search = Service::instance('search')->applyFilters($this->_filterValues)
                ->exec($this->_limit, $this->_offset);

        if ($this->_total = $search->getTotalCount()) {
            $_idList = $search->getResultIdList();
            $_idSet = implode(',', $_idList);

            $this->_listing = Model::factory('website')
                    ->where('id', 'IN', $_idList)
                    ->order_by(DB::expr("FIND_IN_SET(id, '{$_idSet}')"))
                    ->find_all();

            $this->_pager = Pager::factory(Pager::MAIN, $this->_pageNum, $this->_total);
        }
    }
Pager::MAIN - имя конфигурации где задается кол-во записей на странице, view и пр.
 

Adelf

Administrator
Команда форума
A1x
Да что угодно может быть. Даже тот же сфинкс.
Правда ORM в Kohana, помоему, жестко на базу данных завязан, но это не повод...
 

lagoff

Новичок
Полностью согласен с A1x.

Я бы даже на модель не замыкал такую вещь. Вообще ни на что.
Зачем на что-то замыкать тулзу, которая, по большому счету, интерпретирует одно число в два других?
 

Absinthe

жожо
тулзу, которая, по большому счету, интерпретирует одно число в два других?
А эти числа надо откуда-то брать.
Чтобы не несколько раз модель дергать, проще это сделать в ней.
 

lagoff

Новичок
Какие числа? Номер текущей страницы? Из запроса, например, или другого источника.
Количество элементов множества? По-хорошему надо дергать два раза - количество элементов множества надо знать ДО преобразования "страницы" в пару смещение-размер.

А если говорить и задаче получения count'a одновременно с результатом выборки, то она также относится к задаче пагинации, как и пагинация к ней. Никак не относится. И работает этот трюк, насколько я помню, только в Mysql.

Но даже если и так. То сделать что-то типа.
PHP:
$pages = ORM::factory('page')->where('language', '=', $this->language)->order_by('added_at','DESC')->withHiddenCount();
$total_count  = ORM::factory('page')->getLastHiddenCount();
никто не мешает.

Хватит плодить сильносвязанные одноразовые пепелацы.
 

AmdY

Пью пиво
Команда форума
lagoff
ага, а сейчас ещё всё засунуть в пейджинг и в итоге вместо $model->fetchWithPager($from, $perPage); будем клепать каждый раз кучу действий, зато без связанности.
 

lagoff

Новичок
lagoff
ага, а сейчас ещё всё засунуть в пейджинг и в итоге вместо $model->fetchWithPager($from, $perPage); будем клепать каждый раз кучу действий, зато без связанности.
Ага, тонны кода просто =)

PHP:
$repository = ORM::factory('page')->where(...);

$p = Pager::factory()->setOptions(array('setsize' => $repository->getCount(), 'pagesize' => 50))->setCurrentPage($_GET['page']);

$pages = $repository->order(...)->offsetLimit( $p->offset(), $p->limit() )->getObjects();
Да даже так:
PHP:
$p = Pager::factory()->setOptions(array('pagesize' => 50))->setCurrentPage($_GET['page']);
$pages = ORM::factory('page')->where(...)->order(...)->getObjectsWithPager($p);
В одну строчку писать?

Чувствуете потенциал по сравнению с $model->fetchWithPager($from, $perPage); ?
 

AmdY

Пью пиво
Команда форума
lagoff
два статик метода, волшебные строки в качестве параметров, затем инъекция пэйджинга в модель. зачем тогда было заявлять
Хватит плодить сильносвязанные одноразовые пепелацы.
в сравнении с одной строкой инкапсулирующей всю это логику. да - потенциал огромен, если платят за количество строк в коде.
 

lagoff

Новичок
AmdY

два статик метода
тогда уж один, раз счет пошел на штуки. У вас $model же не из воздуха появляется.
волшебные строки в качестве параметров
Волшебные строки... И че? Грех? А по поводу параметров - возможно установки параметров вообще может не быть, если настройки одни и те же везде.
затем инъекция пэйджинга в модель
Ну да. Как вариант. Пример без инъекции я привел тоже.
зачем тогда было заявлять
Не вижу никаких противоречий заявленному.
с одной строкой инкапсулирующей всю это логику
Инкапсулировать? Я бы назвал такой поход захардкодить в том месте где она потребовалась в частном случае.
если платят за количество строк в коде.
=))) Ну вы бы еще сказали, че-нить в духе "ООП ради ООП". Имхо в данном контексте аргумент слабый. Потом вот читаешь такой "экономный" код и один вопрос крутится: "Почему у слона хобот в ж..."

В общем-то, такой подход с зашиванием в "модель" тоже можно использовать, но только в ограниченном числе случаев.

З.Ы. Интересно, а логика расчета видимого диапазона страниц у вас где находится? Тоже в модели? А данные для рендеринга пейджинга вы как собираете?
 

AmdY

Пью пиво
Команда форума
тогда уж один, раз счет пошел на штуки. У вас $model же не из воздуха появляется.
кстати, когда лень, то из воздуха. тупо эвалится новый класс отнаследованный от обстрактной реализации Db\Table.
Ну да. Как вариант. Пример без инъекции я привел тоже.
Это и есть связанность и многократное использование того, что можно связать, но реализовать в ОДНОМ месте для всех моделей. Твои реализации являются частными и программисту нужно помнить какие и в какой последовательности ингридиенты смешивать.
В общем-то, такой подход с зашиванием в "модель" тоже можно использовать, но только в ограниченном числе случаев.
этот способ от ваших отличается лишь одним - он написан однажды и там где нужно. внутри тот же код с отдельным пэеджером и моделью.
З.Ы. Интересно, а логика расчета видимого диапазона страниц у вас где находится? Тоже в модели?
нет, есть отдельный класс pager, просто он вызывается через геттор createPager, чтобы было удобнее расширять и тестировать. Этот объект передаётся в шаблон, где человек может как угодно оформлять вывод? пример есть выше
Потом вот читаешь такой "экономный" код и один вопрос крутится: "Почему у слона хобот в ж..."
собственно вы не привели ни одного аргумента почему такой подход не применим. А у меня железное - меньше писать кода, в разы. Одна строчка для вывода пэйджинга.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Вот! Вот на примерах кода и всплывают махровые теоретики! А то в Фанатской теме-то хорошо было маскироваться под «разницу в терминах»
PHP:
->setOptions(array('setsize' => $repository->getCount()
и
offsetLimit( $p->offset(), $p->limit() )
Замечательный пример — нарушена и инкапсуляция, и полиморфизм. :)
 

fixxxer

К.О.
Партнер клуба
не, модели знать про пейджер это неок

class FooModel extends ListModel{...} // ListModel умеет лимит и оффсет, также загружает count если это явно не отменить

в пейдж-контроллере

PHP:
$FooModel = new FooModel(...);
$Pager = (new Pager($FooModel, $this->perPage))->loadPage($this->args->page);
$this->View->Foo->bind($Pager);
пейджер собственно управляет моделью, в конструкторе первый аргумент обязательно ListModel, рендерит сразу и пейджер и модель.

разве длинно?
 

fixxxer

К.О.
Партнер клуба
что в моем эвале плохого?
он нахрен не нужен.
$request_var = 'REQUEST';
return ${'_' . $request_var};
К суперглобалам нельзя так обращаться, насколько я знаю
да ну
Код:
~$ php -r '$r = "SERVER"; var_dump(${"_".$r});'
array(45) {
  ["LC_PAPER"]=>
  string(11) "ru_RU.UTF-8"
  ["LC_ADDRESS"]=>
  string(11) "ru_RU.UTF-8"
  ["LC_MONETARY"]=>
  string(11) "ru_RU.UTF-8"
  ["TERM_PROGRAM"]=>
  string(9) "iTerm.app"
......
 

Sufir

Я не волшебник, я только учусь
Вот, очень своевременная тема! Как-раз сейчас небольшой проект пишу на ZF, в качестве адаптера для пагинатора использую соответсвенно Zend_Paginator_Adapter_DbSelect в конструктор которого передаётся Zend_Db_Select.
PHP:
        $page = $this->getRequest()->getParam('page');
        $count = $this->getRequest()->getParam('count', Zend_Paginator::getDefaultItemCountPerPage());

        $songs = new Application_Model_Mapper_Songs;

        $adapter = new Application_Model_Paginator($songs->getDbTable()
                    ->select()
                    ->where('trash = ?', false)
                    ->order('id')
                    , $songs);

        $paginator = new Zend_Paginator($adapter);
        $paginator->setItemCountPerPage($count)
                  ->setCurrentPageNumber($page);

        $this->view->paginator = $paginator;
Но не нравится мне наличие Select в контроллере. Получается, что у нас есть DbTable, есть Mapper, есть Model и всё равно в итоге мы имеем в контроллере Select с передачей параметров для фильтрации, джойнами и т.п. Есть мнения, рекомендации?
 
Сверху