Некоторое время назад озадачился поиском решения, которое позволило бы заменить стандартный «паджинатор» (CLinkPager) Yii на такой, который бы вместо номеров страниц писал что-то более внятное. Скажем, первые символы значений полей на последующих страницах. Не нашел и решил написать свой.
Крайне неудобно переключаться между нумерованными страницами, скажем, в списке пользователей. Особенно, когда список большой. Каждое переключение при поиске пользователя на 5-10 страниц, как «гадание на кофейной гуще». То перескочишь нужного пользователя, то наоборот слишком осторожничаешь и не дойдешь. Конечно, поиск помогает, но только тогда, когда точно знаешь фамилию или иные атрибуты. Даже знание имени не помогает, т.к. разных Саш, Маш, Даш, Вань может быть в таблице десятки!
Поиск готового решения, как я написал выше, ничего не дал. Может плохо искал, исправьте, если не прав.
Задача
Пришлось изучать строение CLinkPager и писать свой класс «паджинатора».
Требования к нему были простые:
- отображение значений, а не номеров страниц
- отображение значений целиком или фрагмент
- отображение значений только определенных полей.
Отображение значений, а не номеров страниц — означает, что нужно отобразить первое значение поля каждой страницы. Иными словами, значение поля записи текущей страницы, потом значение поля записи следующей страницы (со смещением равным размеру страницы) и т.д.
Отображение значений целиком или фрагмент — означает, что вывод, например, целой фамилии в «паджинатор» неудобно. Куда удобнее вывести, скажем, первую букву, а лучше две, в общем, столько, сколько будет нужно.
Отображение значений только определенных полей — означает, что выводить в «паджинатор» кусочки значений полей типа число или дата удобства не добавит, хотя, кому как. Поэтому, надо указывать список полей, значения которых будут отображаться в «паджинаторе», а для остальных показывать обычные номера страниц.
Решение
Выяснил, что за отрисовку кнопок отвечает функция createPageButtons() класса CLinkPager. Перекрыть выборочно код создания тех или иных кнопок нельзя, поэтому решил унаследовать класс и дополнить код.
Интересно то, что базовый класс CLinkPager получается универсальным как бы «сам по себе» для любого провайдера данных. Мне же пришлось обрабатывать два класса провайдера данных: CActiveDataProvider, CArrayDataProvider. Каждый отдельно.
При работе с CActiveDataProvider получение значений с каждой страницы получаю с помощью offset:
if ($this->owner->dataProvider instanceof CActiveDataProvider)
{
$pagesize = $this->owner->dataProvider->pagination->pagesize;
$criteria = $this->owner->dataProvider->criteria;
$this->owner->dataProvider->sort->applyOrder($criteria);
$criteria->limit = 1;
for($i=$beginPage;$i<=$endPage;++$i)
{
$criteria->offset = $i*$pagesize;
$m = $this->owner->dataProvider->model->find($criteria);
$buttons[]=$this->createPageButton(is_null($this->length) ? $m->{$field} : mb_substr($m->{$field}, 0, $this->length, 'utf-8'), $i,$this->internalPageCssClass,false,$i==$currentPage);
}
}
При работе с CArrayDataProvider получение значений с каждой страницы получаю по индексу:
if ($this->owner->dataProvider instanceof CArrayDataProvider)
{
$pagesize = $this->owner->dataProvider->pagination->pagesize;
$data = $this->owner->dataProvider->rawData;
for($i=$beginPage;$i<=$endPage;++$i)
{
$m = $data[$i*$pagesize];
$buttons[]=$this->createPageButton(is_null($this->length) ? $m[$field] : mb_substr($m[$field], 0, $this->length, 'utf-8'), $i,$this->internalPageCssClass,false,$i==$currentPage);
}
}
В классе объявил две переменные:
fields — массив имен полей для которых должны отображаться значения, а не номера страниц;
length — длина обрезки значения, если null, то целиком.
Использовать класс, например, в CGridView можно так:
'pager'=>array(
'class' => 'AlxdTitlePager',
'fields'=>array('lastname','firstname','middlename','email'),
'length'=>'2',
'maxButtonCount'=>10,
'firstPageLabel'=>'<<',
'header'=>'',
'hiddenPageCssClass'=>'disabled',
'lastPageLabel'=>'>>',
'nextPageLabel'=>'>',
'selectedPageCssClass'=>'active',
'prevPageLabel'=>'<',
'htmlOptions'=>array('class'=>'pagination')
)
В общем, немного обкатав код решил им поделиться. Кому интересно, может получить исходный код моего класса AlxdTitlePager безвозмездно.
Автор: