Вывод и фильтрация больших таблиц данных с помощью плагина DataTables + ColumnFilter. Часть 1

Веб-разработчики довольно часто сталкиваются с задачей отображения на странице данных в табличной форме с возможностью их сортировки, поиска/фильтрации, разбиения на страницы и удобной навигации по ним. Например, для меня это стало актуально при создании админки для одного сайта. Каждый разработчик решает эту задачу по-своему. Многие не сильно с этим заморачиваются и в результате получаются интерфейсы в стиле ранних версий phpMyAdmin, с полным обновлением страницы после любого клика мышью. Но сейчас уже не начало 2000-х, а значит, пора уже и админки переводить на AJAX и jQuery. Мне в этом очень помог замечательный плагин DataTables, который избавил меня от необходимости изобретать велосипед и писать тонны кода. С его помощью я смог в сжатые сроки придать админке современный вид. Теперь я хочу поделиться некоторым опытом, накопленным за время использования этого плагина.

В этой статье я расскажу как с помощью DataTables и его дополнения Column Filter организовать постраничный вывод больших объемов данных с поддержкой индивидуальной фильтрации по столбцам. В этом случае необходимо задействовать в плагине режим обработки данных на стороне сервера. На сайте плагина есть подробный пример реализации этого режима. Здесь же я рассмотрю практические аспекты применения дополнения Column Filter и особенности реализации обработки данных на стороне сервера в этом случае.

Для тех, кому не терпится посмотреть, как это все работает, вот ссылка на работающий пример, где выводится таблица пользователей гипотетического хабра-подобного сайта). Там же можно найти и исходники примера.

Пример таблицы

В отличие от самого плагина, его дополнение Column Filter, к сожалению, не может похвастать подробной документацией. Множество его возможностей и особенностей почему-то нигде не описаны. Так, в примере настройки Column Filter не указана полная форма инициализации списка (ее можно найти только в исходниках дополнения), вместо нее используется краткая форма:

values: [ 'A', 'B', 'C' ]

которая актуальна только для списков с текстовыми значениями опций, совпадающими с их метками. Это может и годится для простейших статических таблиц, но не подходит для использования с базами данных, где, как правило, значения таких столбцов хранятся отдельно (в другой таблице) и связываются с основной таблицей с помощью ключей. В этом случае следует использовать полную форму инициализации списка:

values: [ {value:1, label:"Текст 1"}, {value:2, label:"Текст 2"}, ... ]

Кроме того, на сайте дополнения почему-то не указано, что в режиме обработки данных на стороне сервера ColumnFilter добавляет в Ajax-запросы к серверу свои дополнительные параметры, которые необходимо учитывать и обрабатывать соответствующим образом в скрипте обработки, иначе индивидуальная фильтрация не будет работать.

На основе примера с сайта DataTables я написал PHP-класс, реализующий обработку данных на стороне сервера, в котором содержатся изменения, необходимые для нормальной работы дополнения Column Filter. Его исходный код можно скачать со страницы примера. А здесь я привожу только интерфейс класса (объявления открытых методов) с комментариями:

abstract class DataTableBase
{

/*
 * Вывод данных из таблицы в формате JSON:
 * @param string $sTable - имя таблицы (используется в запросе SELECT)
 * @param array $aCols - массив столбцов для сортировки и фильтрации
 * @param string $sIndexCol - индексируемый столбец
 * @param array $aColFltFlags - массив флажков, определяющих, подлежит ли столбец общей фильтрации
 * @param string $sFetchCols - список выбираемых столбцов
 * @param string $sTableXtra - дополнение для блока FROM (для INNER JOIN)
 * @param string $sPreCond - необходимое условие (используется в блоке WHERE)
 * @return string|false - данные в формате JSON
 */
function output($sTable, $aCols,
  $sIndexCol='', $aColFltFlags=0, $sFetchCols='', $sTableXtra='', $sPreCond='');

/*
 * Вывод списка в формате JSON:
 * @param string $sTable - имя таблицы
 * @param string $sIdCol - индексируемый столбец
 * @param string $sTitleCol - текстовый столбец
 * @param string $sCond - условие фильтрации
 * @return string|false - список в формате JSON
 */
function outputDataMap($sTable, $sIdCol, $sTitleCol, $sCond='')

/*
 * Подготовка данных для вывода (этот метод должен быть определен в наследнике):
 * @param array $aData - массив данных, извлеченных из БД
 * @return array - подготовленные данные
 */
abstract protected
function buildData($aData);

}

Данный класс поддерживает все типы фильтров для столбцов, используемые в Column Filter:

  • обычный текст;
  • числа и диапазоны чисел;
  • даты и диапазоны дат;
  • списки.

Следует отметить, что диапазоны дат в Column Filter реализуются с помощью Jquery UI, поэтому для их нормальной работы необходимо подключение этого плагина, а также соответствующих стилей и ресурсов. В основном по этой причине (мне не очень нравится этот громоздкий плагин) я и не стал использовать в моем примере фильтр с диапазоном дат, хотя в принципе это возможно – рассмотренный класс поддерживает обработку диапазонов дат.

Пример использования класса DataTableBase:

class DataTableUsers extends DataTableBase
{
function buildData($aData)
{
  $a_res= array();
  $a_badges= $this->sqlDataMap('user_badges', 'id', 'title');
  foreach ($aData as $a_item) {
    $a_row= array();
    $a_row[]= $a_item['login'];
    $a_row[]= $a_item['name'];
    $a_row[]= $a_item['email'];
    $a_row[]= $a_item['karma'];
    $a_row[]= isset($a_badges[$id= $a_item['badge']])? $a_badges[$id]: '';
    $a_res[]= $a_row;
  }
  return $a_res;
}

function outputWrap()
{
  return $this->output(
    'users',
    array('login', 'name', 'email', 'karma', 'badge'),
    'user_id',
    array(true, true, true, true, 0)
  );
}
}

/* Код подключения к БД */
require_once 'db_init.php';

if (!isset($_GET['action'])) return;
$oDt= new DataTableUsers();
switch ($_GET['action']) {
case 'data':
  echo $oDt->outputWrap();
  break;
case 'col_badges':
  if ($s= $oDt->outputDataMap('user_badges', 'id', 'title'))
    echo $s;
  break;
}

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>