Удобный «паджинатор»

в 6:49, , рубрики: pager, yii, yii framework

Некоторое время назад озадачился поиском решения, которое позволило бы заменить стандартный «паджинатор» (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 безвозмездно.

Автор:

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js