Reusing Drupal's pager for non-SQL data

The last couple of days I have been integrating a number of SOAP services in a Drupal site. The SOAP operation I'm calling provides access to a large set of data and it supports a page parameter which is very similar to the way Drupal shows large lists across multiple pages using a pager showing "1 2 ... next> last>>".

I was hoping to reuse the existing Drupal pager functionality but I couldn't find any documentation that explains how to use the pager in combination with non-SQL data. I looked into the pager.inc source code and it turns out it is not too hard to do.

Here's a small example that shows how to create a page that lists a subset of data and adds a pager at the bottom to navigate back and forth.

First there are two dummy helper functions that provide the number of items per page and the total number of pages.

function mymodule_items_per_page()
{
  return 8;
}

function mymodule_number_of_pages()
{
  return 12;
}

Next there is a function that is responsible for providing the data to show on a specific page:

/*
 *  Generate some dummy data.
 */
function mymodule_generate_list($page)
{
  $items_per_page = mymodule_items_per_page();
  for ($i = 0; $i 

And finally there is the menu callback that does the real work: display a list ot items (including a pager at the bottom).

function mymodule_show_list()
{
  // Two global variables needed by the pager.
  // Taken from pager_query() in pager.inc
  global $pager_page_array, $pager_total;

  $output = '';

  // Grab the 'page' query parameter.
  // Taken from pager_query() in pager.inc
  $page = isset($_GET['page']) ? $_GET['page'] : '';

  // Convert comma-separated $page to an array, used by other functions.
  // Taken from pager_query() in pager.inc
  $pager_page_array = explode(',', $page);

  // Generate the data for page the requested and add it to the output.
  foreach (mymodule_generate_list($page) as $item)
  {
    $output .= '<p>' . $item . '</p>';
  }

  // Put some magic in the two global variables
  // Based on code in pager_query() in pager.inc
  $pager_total[0] = mymodule_number_of_pages();
  $pager_page_array[0] =
    max(0, min(
      (int)$pager_page_array[0],
      ((int)$pager_total[0]) - 1)
    );
 	
  // Add the pager to the output.
  $output .= theme('pager', NULL, mymodule_items_per_page(), 0);

  return $output;
}

This worked for me in Drupal 5. I'm not sure whether this will work in Drupal 6 but I'm pretty sure it will be very similar.

Update: The reference to $element mentioned in the comments has been replaced by "0". It was a left over from copy-pasted code from Drupal core.

Topic: 

12 Comments

You have a missing

You have a missing parenthesis in the following sentence, it should read this:

$pager_page_array[0] = max(0, min((int)$pager_page_array[0], ( (int)$pager_total[0]) - 1));

code

code error:
$pager_page_array[0] =
max(0, min(
(int)$pager_page_array[0],
(int)$pager_total[0]) - 1)
);

there are two ( opened and ) three close

-----------------
If I have a function mymodule_xxx() {}

how can use your code for the pagination?

Obiouvsly if I have an a sql inner (wher I can use pager_query) I should write this
function theme_mymodule_xxx($form) {
....
...
$output .= theme('pager');
}

When send answer can send also at my email that you post new answer,thanks

Example: A) function

Example:
A)
function mymodule_xxx() {
$result = pager_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
$roles = array();
while ($role = db_fetch_object($result)) {$roles[$role->rid] = $role->name; }

$form['my-roles'] = array
( '#type' => 'checkboxes',
'#options' => $roles );
}
$form['submit'] = array('#type' => 'submit', '#value' => t('Save settings'));
return $form;
}
B)
function theme_mymodule_xxx($form) {
$header = array(t('Users'));
$rows = array();
foreach (element_children($form['my-roles']) as $field) {
$row = array();
$row[] = drupal_render($form['my-roles'][$field]);
$rows[] = $row;
}
$output = theme('table', $header, $rows);
$output .= drupal_render($form['submit']);
$output .= theme('pager');

return $output;
}

With A and B I can have list roles and make pagination

Now see that $roles = user_roles(true) is also the same array and the function A is so:
A
function mymodule_xxx() {
$roles = user_roles(true);
$form['my-roles'] = array
( '#type' => 'checkboxes',
'#options' => $roles );

$form['submit'] = array('#type' => 'submit', '#value' => t('Save settings'));
return $form;
}

how must to be function B?

I appreciate this post,

I appreciate this post, because it helped me figure this whole thing out... However, just for clarity's sake, I would recommend you bold the line which utilizes the global keyword, because that line really shows how it works, and the rest is just minutia.

Thanks,
Chris

I can't seem to get this

I can't seem to get this working for Drupal 6, any change of putting up an example. I seem to be able to get the pager to display, but with no actual content. Great post litrik, there doesn't seem to be a great amount of information on the web about this.