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

~WR~

Новичок
Заинтересовало. Посмотрел код.

С ходу увидел:
PHP:
    public function __construct($limit, $link_count, $page_var_name = 'page', $separator_var_name = 'sep', $request = 'REQUEST')
    {
        $this->limit = intval($limit);
        $this->link_count = intval($link_count);

        $this->page_var_name = $page_var_name;
        $this->separator_var_name = $separator_var_name;

        $request_array_name = '_' . ltrim($request, '_');
        $request = eval("return \$$request_array_name;");
Уязвимость по входящему аргументу $request. Понятно, что в 99% случаев там будет строка с хардкодом. Но потом какой-нибудь Вася это вынесет, например, в настройки. Не со зла, конечно. Но именно так дырки и появляются.

------------------

По опыту создания пагинаций:

Не всем подходят голые суперглобалы. Часто используются какие-то обертки, которые фильтруют и модифицируют входящие переменные. И именно измененные версии хочется подставлять в пагинацию. Также часто нужен не весь массив, а какие-то отдельные ключи. Необходима возможно напрямую передать массив с нужными данными.

И пусть последний аргумент принимает такой массив. Этим же решится проблема указания суперглобала. Если нужен только голый $_GET, то и передаем его. Если Null, значит используем $_REQUEST по умолчанию.

Попозже еще посмотрю ^_^
 

atv

Новичок
Вау! А в чём принципиальная разница между передачей в параметре $request = 'REQUEST' названия глобального массива, от передачи самого глобального массива? Кроме того что во втором случае на две строчки кода меньше будет?
 

Духовность™

Продвинутый новичок
это отголоски старых лохматых годов, никак руки не доходят. в идеале надо предусмотреть возможность передачи туда любого объекта запроса или суперглобального массива GPR
 

Adelf

Administrator
Команда форума
Духовность™, а вот такой вот eval тоже входит в твое понимание "идеального кода"? Ты ж говорил он у тебя всегда идеальный.
 

atv

Новичок
Adelf, чего прицепился. Он уже признал, что код не идеален и подлежит исправлению. Признание ошибки - первый шаг на пути к исправлению.

что в моем эвале плохого?
Ай-яй-яй. Вот кто тебя за язык тянул? А вместо евала можно просто сделать $$request_array_name, зачем там евал...
 
  • Like
Реакции: AmdY

Adelf

Administrator
Команда форума
atv
Да я расстроился просто. Бывают же люди - идеальный код пишут. Но то, что я - говнокодер :)

Духовность™
Плохо в нем то, что он есть.
 

~WR~

Новичок
PHP:
$$request_array_name
К суперглобалам нельзя так обращаться, насколько я знаю :)

Духовность™
Не хотите выложить исходный код на github? Всех дел на 5 минут, но насколько же удобнее в нем читать код и следить за проектами.
 

Adelf

Administrator
Команда форума
К суперглобалам нельзя так обращаться, насколько я знаю
Ноги тут растут с "var_name". Да. PHP - язык динамический. Многое позволяет. Но злоупотреблять не стоит. Как говорил atv, передать напрямую массив, а не его имя - не только короче на два символа, но гораздо правильнее.
 

Absinthe

жожо
Подниму тему, мое мнение, как должен работать paginator:

В контроллере.:
$items = Item::scope()->order("name")->page($page);

И в виде хелпер:
<?= paginate($items) ?>
 

флоппик

promotor fidei
Команда форума
Партнер клуба
PHP:
public function action_index()
    {
        $pages = ORM::factory('page')->where('language', '=', $this->language)->order_by('added_at','DESC');
        $paginate = Paginate::factory($pages)->paginate()->render();
        $pages = $pages->find_all();

        $this->set('pages', $pages)
             ->set('paginate', $paginate)
             ->set('language', $this->language);
    }
Вчера написал для коханы.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
PHP:
->paginate($page, $items_per_page, $url)
Если не переданы, определяются из конфигурации или вычисляются автоматически, типа (
PHP:
$page = Arr::get($_GET, $config->get('url_key', 'page'));
)
 

AmdY

Пью пиво
Команда форума
я для гибкости в классе пейджер просто генерю объект, а затем в шаблоне его декорирую как угодно. соответственно
PHP:
<? if ($PAGER->getPages() > 1) { ?>
<ul class="pager">
    <? for ($i=1;$i<=$PAGER->getPages();$i++) { ?>
    <li>
        <?php if ($PAGER->getOffset()!=$i) { ?>
        <a href="<?=$this->baseUrl?><?if ($i>1): ?>p:<?=$i?>/<? endif;?>"><?=$i?></a>
        <?php } else { ?>
        <span class="current"><?=$i?></span>
        <?php } ?>
    </li>
    <? }?>
</ul>
<? } ?>
метод в модели, который готовит данные
PHP:
public function findWithPager($offset = 0, $limit = 10)
    {
        $select = $this->getSelect();
        if (!preg_match('~\s*SQL_CALC_FOUND_ROWS~i', $select))
        {
            $this->getSelect()->set("SQL_CALC_FOUND_ROWS $select");
        }
        $this->setLimit($limit)
                ->setOffset($offset);
        $retVal = array(
            'offset' => $offset,
            'limit' => $limit,
        );
        $retVal['data'] = $this->getConnection()
                ->fetchAll($this->getQuery(), $this->getWhere()->getData());
        $count = $this->getConnection()
                ->fetchOne('SELECT FOUND_ROWS()');
        $retVal['total'] = $count['FOUND_ROWS()'];
        $retVal['pager'] = $this->createPager($offset, $retVal['total'], $limit);
        $this->setData($retVal, true);
        return $retVal;
    }
 

AmdY

Пью пиво
Команда форума
Духовность™
вот именно, у тебя какой-то монструозный объект пэйджер, который и данные таскает и пэйджинг расчитывает и отрысовывает его.
в моём варианте пэйджер просто рассчитывает страницы, благодаря чему он качует со времён ZF 0.6 в проекты на разных фреймворках без каких либо изменений.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
я для гибкости в классе пейджер просто генерю объект, а затем в шаблоне его декорирую как угодно. соответственно
Я тоже. Просто у меня имя шаблона по умолчанию берется из конфигурации.

Но я воздействую пейджером на модель, что бы задать ей лимиты, поэтому это работает с любой моделью, а не только той, у которой есть специальный метод, и даже можно просто на Database_Select воздействовать.
 
  • Like
Реакции: AmdY

флоппик

promotor fidei
Команда форума
Партнер клуба
На самом деле, у меня можно (а может, и нужно) заставить модель сделать ->find_all() уже из пагинатора->paginate(), и вернуть сразу отрендеренный результат, тогда все станет особенно читаемо и красиво, типа,
PHP:
$pages = ORM::factory('page')->where('language', '=', $this->language)->order_by('added_at','DESC');
$paginate = Paginate::factory($pages)->paginate();
$this->set('pages', $pages)
       ->set('paginate', $paginate)
       ->set('language', $this->language);
 

A1x

Новичок
я бы не стал делать вообще никакой зависимости между моделью и классом пагинации
 
Сверху