Drupal custom pager and table header sortable without SQL query

Profile picture for user Andriy Dmytriv

There are cases when an array of information should be separated and displayed by page without extending the query like this.

$query->extend('PagerDefault')->limit($pager).
$query->extend('TableSort')->orderByHeader($header).

There are many reasons for this. One way to use this code is when there is a ready-made array of data received in another way, for example through API or some pre-recorded data.

Although these code examples, described for Drupal 7, can be used without any changes for Drupal 8. Because the functions that are used here have been moved from Drupal 7 to Drupal 8.

Сustom pager

  $header = array('Name');
  $zodiac = array(
    'Aquarius',
    'Pisces',
    'Aries',
    'Taurus',
    'Gemini',
    'Cancer',
    'Leo',
    'Virgo',
    'Libra',
    'Scorpio',
    'Sagittarius',
    'Capricorn',
  );

  $zodiac_piece = _return_pager_for_array($zodiac, 3);

  // Wrapper for rows
  foreach ($zodiac_piece as $item) {
    $rows[] = array($item);
  }

  // Create table and pager
  $element['table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('There is no data available.'),
  );

  $element['pager'] = array(
    '#theme' => 'pager',
  );

  return $element;

$zodiac —  here we have an array that needs to be split into pages.

_return_pager_for_array() — in this function we perform the main part.

Wrapper for rows.

  foreach ($zodiac_piece as $item) {
    $rows[] = array($item);
  }

 Create and return sortable table.

  $element['table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('There is no data available.'),
  );

  $element['pager'] = array(
    '#theme' => 'pager',
  );

  return $element;

 Split array for the pager.

/**
 * Split array for pager.
 *
 * @param array $items
 *   Items which need split
 *
 * @param integer $num_page
 *   How many items view in page
 *
 * @return array
 */
function _return_pager_for_array($items, $num_page) {
  // Get total items count
  $total = count($items);
  // Get the number of the current page
  $current_page = pager_default_initialize($total, $num_page);
  // Split an array into chunks
  $chunks = array_chunk($items, $num_page);
  // Return current group item
  $current_page_items = $chunks[$current_page];

  return $current_page_items;
}

Get the total number of records, in our case, it will be 12.

$total = count($items);

  Get the number of the current page using the standard Drupal function. It will be [0, 1, 2, 3].

$current_page = pager_default_initialize($total, $num_page);

Split an array into chunks, after that, it will look like this:

Chunks array

Then we return the current group item. When we go to the pages, there will be specific parts output of our array of information.

Next, I will describe how to do sorting tables without SQL query.

Table header sortable without SQL query

  $header = array(
    array('data' => t('Name'), 'field' => 'name'),
  );
  $zodiac = array(
    'Aquarius',
    'Pis ces',
    'Aries',
    'Taurus',
    'Gemini',
    'Cancer',
    'Leo',
    'Virgo',
    'Libra',
    'Scorpio',
    'Sagittarius',
    'Capricorn',
  );

  $zodiac_piece = _return_pager_for_array($zodiac, 3);

  // Wrapper for rows
  foreach ($zodiac_piece as $item) {
    $rows[] = array('name' => $item);
  }

  $rows = _records_nonsql_sort($rows, $header);

  // Create table and pager
  $element['table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('There is no data available.'),
  );

  $element['pager'] = array(
    '#theme' => 'pager',
  );

  return $element;

Pay attention to the following pieces of code:

  $header = array(
    array('data' => t('Name'), 'field' => 'name'),
  );

  foreach ($zodiac_piece as $item) {
    $rows[] = array('name' => $item);
  }

 

This format is required, otherwise, it will not work.

In this code the main role is played by Drupal functions tablesort_get_order() and tablesort_get_sort(). These functions give you a column and how to sort it. Then we operate these data.

/**
 * Custom table sort
 *
 * @param array $rows
 *   Table rows which need sortable
 *
 * @param array $header
 *   Table header
 *
 * @param $flag
 *
 * @return array
 *
 * @see http://php.net/manual/ru/function.sort.php
 */
function _records_nonsql_sort($rows, $header, $flag = SORT_STRING|SORT_FLAG_CASE) {
  $order = tablesort_get_order($header);
  $sort = tablesort_get_sort($header);
  $column = $order['sql'];
  foreach ($rows as $row) {
    $temp_array[] = $row[$column];
  }
  if ($sort == 'asc') {
    asort($temp_array, $flag);
  }
  else {
    arsort($temp_array, $flag);
  }

  foreach ($temp_array as $index => $data) {
    $new_rows[] = $rows[$index];
  }

  return $new_rows;
}

Finally, there's a result:

Example table sort next

Example drupal table sort

Some handy notes:

Official sample from drupal.org

https://www.drupal.org/docs/7/creating-custom-modules/howtos/paging-non-sql-data

Also the answer to the question from drupal.stackexchange.com

https://drupal.stackexchange.com/questions/14889/can-tablesort-be-used-without-a-query