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.

12 Comments
Interesting approach but
Submitted by yaph on
Interesting approach but where does $element come from?
No idea where $element comes
Submitted by litrik on
No idea where $element comes from, but it works like this :)
$pager_page_array is a weird global variable. All kinds of funky stuff happens to it. If I'd understand what it does I might be able to get rid of the $element variable. But right now I don't so it is still there.
The reference to $element
Submitted by litrik on
The reference to $element was a left over from copy-pasted code from Drupal core. It can be replaced by "0". The blog post has been updated.
You have a missing
Submitted by Anonymous on
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));
The $element var is in case
Submitted by Anonymous on
The $element var is in case you have more than one pager in the same page.
code
Submitted by Anonymous on
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
I have fixed the code
Submitted by litrik on
I have fixed the code snippet. Thanks.
I do not understand your question about mymodule_xxx(). What are you trying to achieve?
Example: A) function
Submitted by Anonymous on
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'm sorry but I'm not able
Submitted by litrik on
I'm sorry but I'm not able to help you. I suggest you ask your question in the forum.
I appreciate this post,
Submitted by Chris on
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 confirm this array pager
Submitted by Vacilando on
I confirm this array pager trick works perfectly also under Drupal 6. Thanks!
I can't seem to get this
Submitted by Web Assistant on
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.