Theming a Drupal table
Wed, 2008/12/03 - 19:09 — balu
Recently I had to explain the how Drupal handles table theming, so I decided i’ll try writing it down for others to benefit. Hope its any good. First I’ll write a bit about the idea behind the whole process, and at the end I’ll show this on a concrete example. Comments are welcome.
Data and representation
Drupal lives according to the philosophy that data structure (your raw data, for instance your columns of numbers from a table) and the representation (the actual HTML code that is being printed) are distinct. This idea coupled with the aim to expose the representation layer for overrides (so you can make your own theme, that creates a different table for instance) gave birth to the theme system that is in Drupal now.
How this works in action? The workflow is the following. First we get the data, and structure it in a certain way. Generally this means we populate an array according to specifications. Our theming functions understand this specification, and create an HTML structure out of it. Since the data structure is fixed, we can implement our own theming functions with relative ease, to provide custom output, which can even be XML for instance.
Example
Getting the data
Assume we have a data query from the database, and we loop through each row of that query result, saving it to the temporary $data object. In Drupal the commonly used method for this is:
$result = db_query('SELECT ....');
while ($data = db_fetch_object($result)) {
// We assemble the data for theming here, but '''no HTML''' generated yet!
}
Information that we want to pass to the Drupal core theme_table() function has to be built in a specific way. It takes some time to get used to, but its actually quite logical. Each logical entity, let it be a row, cell, or the table can be specified two ways. Either as an array, where one element has to be the actual data in that entity (say cell content), the rest are attributes used to render the entity, for example class.
This is how you can create a cell using an array: $cell = array('data' => $data->col, 'class' => 'nice-cell');, but when you don’t need specific attributes a simple $cell = $data->col; suffices as well.
After we have our cell we need to add it to the list of cells in a row, which will be an array too. A commonly used pattern to assemble a series of rows is the following:
while ($data = db_fetch_object($result)) {
$row = array();
$row[] = array('data' => $data->col1, 'class' => 'nice-cell');
$row[] = array('data' => $data->col2, 'class' => 'nice-cell');
$row[] = array('data' => $data->col3, 'class' => 'nice-cell');
// and so on until we have all our cells for a row, which is when we store it.
$rows[] = $row;
}
After a row is collected we append it to a master $rows array, which will be later passed to the theme function. Its an easy mistake not to declare the $row array at the beginning of the loop, its necessary to reset it, since we don’t want it to keep stacking up.
Now basically we have our abstract data. No representation so far. theme_table is going to handle this:
$output = theme('table', $rows, $header);
We haven’t covered $headers so far, so lets do them too, same syntax, although beware that with the core theme function the rendered <thead> can not be customized, $header = array('data' => $stuff, 'class' => 'header'); WILL NOT work.
$h_cell = array('data' => t('Column 1'), 'class' => 'header-cell-class'); will however. An interesting possibility is that using a 'header' => TRUE element one can make cells render as <th> instead of <td>, when placed into the first argument of the theme_table() (which is normally the data).
Comments
Tue, 2009/01/27 - 09:01 — Stan Brower (not verified)
Hi! Thanks for the great
Hi! Thanks for the great guide. I am new to Drupal and trying to learn more so any help is a good addition to the knowledge.This surely helps.Your efforts are highly appreciated.Thanks for posting.
Tue, 2009/03/17 - 19:09 — Bryan (not verified)
Thanks for the example, it
Thanks for the example, it was helpful.
Tue, 2009/06/02 - 17:58 — Greg (not verified)
Just a heads up on a typo.
Just a heads up on a typo. For each row:
$row[] = array('data' => $data->col1, 'class' => 'nice-cell);
...you're missing the closing "'" after the class name.
Thanks for the writeup.
Sat, 2009/08/22 - 10:29 — Club Penguin Cheats (not verified)
I am new to Drupal and trying
I am new to Drupal and trying to learn more so any help is a good addition to the knowledge.This surely helps.
Wed, 2009/11/04 - 00:54 — Tyler Walters (not verified)
Thanks for the info! For
Thanks for the info!
For cases where the results are lengthy, you can use pagination with just a little bit of modifications:
- Set a variable for the limit of results for each page, for example: $limit = 50;
- Instead of db_query, use pager_query, and also pass the # of results per page, like this:
$result = pager_query($sql, $limit); - After you add the theme’d table to the output, next add the pagination controls, like this:
$output = theme('table', $rows, $header);
$output .= theme('pager', NULL, $limit, 0);
Wed, 2009/12/23 - 20:42 — alışveriş (not verified)
Thank you very much for the
Thank you very much for the excellent and useful subject.