background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount
Eric.London's picture

In this tutorial, I'll show you how you can create a table with re-sortable column headers and pagination from custom SQL. I strongly recommend you attempt to implement this functionality using the Views module first :)

<?php
/**
* Implements hook_menu()
*/
function helper_menu() {

 
$items = array();
 
 
$items['pager-test'] = array(
   
'title' => t('Pager Test'),
   
'description' => t('Pager Test'),
   
'page callback' => 'helper_page_callback_pager_test',
   
'access arguments' => array('access content'),
   
'type' => MENU_CALLBACK,
  );
 
  return
$items;

}

/**
* Implements page callback for pager-test url
*/
function helper_page_callback_pager_test() {

 
// define number of results per page
 
$number_results = 10;

 
// define a list of columns to select
 
$columns = array(
   
'nid' => t('ID'),
   
'type' => t('Type'),
   
'title' => t('Title'),
  );

 
// define sql to fetch results
 
$sql = "select %s from {node} where status = 1";

 
// define sql to fetch number of results
 
$sql_count = "select count(*) from {node} where status = 1";

 
// create resort header from column list
 
$header = array();
  foreach (
$columns as $key => $value) {
   
$header[] = array(
     
'data' => $value,
     
'field' => $key,
    );
  }
 
 
// add tablesort to SQL
 
$sql .= tablesort_sql($header);

 
// execute query
 
$resource = pager_query($sql, $number_results, 0, $sql_count, implode(', ', array_keys($columns)));

 
// fetch results
 
$results = array();
  while (
$row = db_fetch_array($resource)) {
   
$results[] = $row
  }

 
// define variable to contain page callback output
 
$output = "";
 
 
// create table html
 
$output .= theme('table', $header, $results);
 
 
// create pager html
 
$output .= theme('pager', NULL, $number_results, 0);

  return
$output;

}
?>

The above code results in the following table:

Pager Test

Eric.London's picture

Functionality that I regularly create in applications is the ability to take a SQL statement and return a table of results for reports, debugging, etc. Here's a helper function I created to implement this functionality. I purposely left off pagination, sortable columns, and other features to focus on how the Drupal theme_table() function operates. This helper function will use the column names from the SQL as the table column headers, so make sure they are properly formatted.

<?php
// first, I defined this function in my module:
function _MYMODULE_sql_to_table($sql) {
   
 
$html = "";
   
 
// execute sql
 
$resource = db_query($sql);
   
 
// fetch database results in an array
 
$results = array();
  while (
$row = db_fetch_array($resource)) $results[] = $row;
   
 
// ensure results exist
 
if (!count($results)) {
   
$html .= "Sorry, no results could be found.";
    return
$html;   
  }

 
// create an array to contain all table rows
 
$rows = array();
   
 
// get a list of column headers
 
$columnNames = array_keys($results[0]);
   
 
// loop through results and create table rows
 
foreach ($results as $key => $data) {

   
// create row data
   
$row = array();
   
   
// loop through column names
   
foreach ($columnNames as $c) {
     
$row[] = array(
       
'data' => $data[$c],
       
'class' => strtolower(str_replace(' ', '-', $c)),
      );
    }

   
// add row to rows array
   
$rows[] = $row;
       
  }
   
 
// loop through column names and create headers
 
$header = array();
  foreach (
$columnNames as $c) {
   
$header[] = array(
     
'data' => $c,
     
'class' => strtolower(str_replace(' ', '-', $c)),
    );
  }
   
 
// generate table html
 
$html .= theme('table', $header, $rows);
   
  return
$html;
   
}

// then you can call it in your code...
function _MYMODULE_some_page_callback() {
 
 
$html = "";

 
$sql = "select * from {node}";

 
$html .= _MYMODULE_sql_to_table($sql);

  return
$html;
}
?>

Eric.London's picture

I'm working on a piece of code that outputs a variable number of node fields into a table that has one row. I decided to use a table and tds to solve the following: 1) maintaining a true MVC by keeping my CSS (view) separate from my code (model); and 2) implement a variable number column solution that does not require a hard-coded width. Anyway... After implementing the table, I realized large images in my content would skew the overall width of each td. I decided to write some jQuery to resize images in my content automatically. This code figures out the overall width of my page (parent div of the table) and the padding on each td, and adjusts as necessary...

<?php
$(document).ready(function(){
   
 
// get width of main column
 
var mainWidth = $('#MYPARENTDIV').innerWidth();

 
// get number of columns
 
tdCount = $('td', 'table.MYTABLECLASS tr').length;
   
 
// tally td padding
 
var tdPadding = 0;
  $(
'td', 'table.MYTABLECLASS tr').each(function(){
   
tdPadding += $(this).innerWidth() - $(this).width();
  });
   
 
// calculate new max image width
 
var maxWidth = (mainWidth - tdPadding) / tdCount;
   
 
// adjust image dimensions
 
$('img', 'table.MYTABLECLASS tr td').each(function(i){
   
// check the width of the image
   
if ($(this).width() > maxWidth) {
     
// calculate new image dimensions
     
newWidth = maxWidth;
     
newHeight = $(this).height() / ( $(this).width() / maxWidth );
           
     
// set new image dimensions
     
$(this).height(newHeight).width(newWidth);
    }
  });   
});
?>

Here is a quick and powerful way to override the theme engine to get the Views module to display your content anyway you'd like. First, create a view that provides a page view. Choose "List View" as the view type. Make sure you add all the fields you'd like to include in this view. Add your filters and sort criteria as necessary. Save your view and make sure it's working. Go to the URL you assigned to the page view. You should see a <ul> list of the fields you chose to include.

Next, go to the theme wizard page (admin/build/views/wizard). Choose your view from the list and choose "simple list" as the theme type. Click on the Select Theme Type button. On the next page, you'll see two textareas full of code. Copy and past the top code into you template.php file. As for the bottom code, create a new file in your theme directory called "views-list-YOURVIEWNAME.tpl.php".

If you reload your page view, it should look the same. Now, you can alter those two code segments to get the view to appear the way you'd like. Changing the "views-list-YOURVIEWNAME.tpl.php" file will alter how each node is themed.

For example, you could use this technique to create a different table layout. The default table layout included in the views module will display a node's data in each <tr>, separating each field in a <td>. Locate the following code in you template.php file:

<?php
if ($items) {
  return
theme('item_list', $items);
}
?>

You could replace the "item_list theme type with something like this...

<?php
return "<table><tr>" . implode("", $items) . "</tr></table>";
?>

You'll also have to open up the "views-list-YOURVIEWNAME.tpl.php" file and enclose the entire contents in a <td></td>. In this case, you could also add some conditional code to segment the rows into 3 columns, etc.

Syndicate content