Experiment: Datatable class

Output a HTML data table in PHP easily

In my recent meanderings though object-oriented land, I wanted something to help me get my head round this pretty important method of programming. If I call myself a developer I really should know what most developers in the world do, shouldn’t I? What I needed as something to get my teeth into, an example from my own experience I could turn into OOP code.

And what better than something for my projectGenie system. In particular I wanted to simplify the bloated code I used to output HTML tables of data, and turning it into a class seemed to be the best way to do it.

About OOP

So, firstly an introduction about object-orientated programming, and bear with me because I’m still learning here. This style of development sees most things as ‘objects’ A car is an object, so is a house, so is a record in a database. Pretty much all objects have properties. A property is something that we can use to describe part of the object: the car is read, the house has 4 bedroom, the database row has a field called ‘ID’ with the value ‘123’. An objects properties could b described as variables outside of the object.

Objects also have methods. A method is something we can do with the object. We can start the car, unlock the house, or change the database row. A method in an object would be called a function outside of that object. There may be some technical differences, but functions and methods are pretty much the same thing.

A simple example

To be honest none of that, although I read it many times in many different places, made much sense to me until I actually looked at a simple objects’ code and could translate that into what I wanted. So I’ll do the same with you, just look at this. This is in PHP, but any OOP language will work the same way even if the syntax is different.

<?php

class car {
	
	// the properties
	$this->color = "red";
	$this->engineSize = 1.8;
	$this->doors = 5;
	$this->engineStarted = false;
	
	// a couple of methods
	function start(){
		$this->engineStarted = true;
	}
	function paint($color){
		$this->color = $color;
	}
}

?>

Now you may be thinking ‘Hurrah, but so what?’ and I don’t blame you. After all, that’s nothing you can’t do with just a few varibles and functions. But what have we done? We’ve created a class, which is a template for an object. It’s a class called ‘car’ and has a few properties and methods. But how do we use this; at the moment it’s just sitting there waiting for someone to come and rev the engine up. We have to create the car like this:

<?php

$myCar = new car();
	
// set some of the properties
$myCar->color = "green";
$myCar->engineSize = 1.1;

?>

So now $mycar is an instance of the object ‘car’, and it’s green and has a measly 1.1 engine. Let’s paint it black, shall we?

<?php

// get out the paint
$myCar->paint("black");

?>

And now we have a little KITT car. Lovely.

Now it’s your turn

Imagine you want to create an object. What object would it be? Something that exists already, or something completely new? What properties would it have (how could you describe it) ? And what methods would it have (what could you do with it) ? Here’s something I just thought of:

<?php

class alienLifeForm {
	
	// the properties
	$this->numberOfLegs = 19;
	$this->stapleDiet = "Wierd alien plantlife, and human flesh on Sundays";
	$this->penchantFor = array("Country and Western music","Knitting","Watersports");
	
	// a couple of methods
	function sayHello(){
		$this->tentacles = "waving";
	}
	function eatHuman($color){
		$this->tentacles = "chomping";
	}
}

?>

See how easy that is? Fantastic, eh?

The datatable class

So now we’re all OK with the general idea of objects, classes, properties and methods, let me introduce you to a friend of mine; the DataTable object. This nifty object, all neatly wrapped up in a class for your delictation, allows the canny PHP developer to easily output HTML tables containing data. Not only that, but you can style the fields, add styles and IDs to rows, and generally have a whale of a time.

The full code is below, and you can dissect that if you want. For now I’m just going to show you a simple example that demonstrates the capabilities of the object. Follow the comments in the code, and click here for the example.


<?php

// Create the new datatable
$t = new DataTable();

// Set the field names using the property 'fields'
// these are in a array of strings
$t->fields = array("ID","Title","Description");

// Set the format of the fields using the property 'fieldFormat'
// each field format is a string
// Use '%%[field id]' to display the corresponding field value,
// 1 for the first field, 2 for the next field etc

// Example 1: this displays field 1 in strong tags
$t->fieldFormat(1, "<strong>%%1</strong>");

// Example 2: this displays field 2 with a hyperlink to field 1
$t->fieldFormat(2, "<a href=\"%%1\">%%2</a>");

// Example 3: this displays a phrase in emphasis tags with fields 3
// and 1 in the text
$t->fieldFormat(3, "<em>%%3 with ID %%1</em>");

// Add rows to the table using the 'addRow' method
// each row is an array
$t->addRow(array("1", "Link 1", "This is link 1"));
$t->addRow(array("2", "Link 2", "This is link 2"));
$t->addRow(array("3", "Link 3", "This is link 3"));
$t->addRow(array("4", "Link 4", "This is link 4"));
$t->addRow(array("5", "Link 5", "This is link 5"));

// This row will span the width of the table, as there are less fields
// than there should be. The datatable object will automatically
// pad missing columns to the end of the row
// This row will have an ID of 'insertedrow' and a class of 'glow'
$t->addRow(array("Inserted row"), array("class"=>"glow","id"=>"t$id"));

// Add some more rows
$t->addRow(array("6", "Link 6", "This is link 6"));
$t->addRow(array("7", "Link 7", "This is link 7"));
$t->addRow(array("8", "Link 8", "This is link 8"));
$t->addRow(array("9", "Link 9", "This is link 9"));
$t->addRow(array("10", "Link 10", "This is link 10"));

// Finally, show the data table
$t->showDataTable();

?>

So the only thing remaining is to give you the script to download. And here it is in it’s completeness, ready for copying and pasting. The usual GPL licence applies.

<?php
// ======================================
// THE PHP DATATABLE CLASS
// Author: Chris Taylor, stillbreathing.co.uk
// This work is protected under the GPL Licence
// Full details at http://www.opensource.org/licenses/gpl-license.php
// ======================================

class DataTable
{
	// initial variables
	function __construct() {
		// set some variables
		$this->summary = "Table summary";
		$this->caption = "Table caption";
		$this->altClasses = array("","alt");
		$this->fields = array("No fields set");
		$this->rows = array();
		$this->rowParams = array();
		$this->headerRepeat = 0;
		$this->fieldFormats = array();
	}
	
	// bind a MySQL mysql_fetch_array array to the datatable
	function dataBind($arr){
		// set the fields to nothing
		$this->fields = array();
		// loop the field names and add them
		foreach($arr as $key => $value){
           $this->addField($key); 
        }
        // set the rows to nothing
        $this->rows = array();
        // loop each row and add it
		for ($r=0; $r<count($arr); $r++){
			$this->addRow($arr[$r]);
		}
	}
	
	// add a field
	function addField($fieldName){
		// add the values to a new row
		$this->fields[] = $fieldName;
	}
	
	// add a row
	function addRow($values,$params=array()){
		// add the values to a new row
		$this->rows[count($this->rows)] = $values;
		// if there are row parameters set
		if (count($params)>0){
			// add any parameters
			$this->rowParams[count($this->rows)-1] = $params;
		}
	}
	
	// format a field
	function formatField($fieldNo, $rowNo){
		$value = "";
		// if the field has a format
		if ($this->fieldFormats[$fieldNo+1]){
			$output = $this->fieldFormats[$fieldNo+1];
			// modify the field value with the format
			for ($y=0; $y<count($this->rows[$rowNo]); $y++){
				$fieldId = $y+1;
				$value .= "[$y] ";
				$output = preg_replace("/%%$fieldId/", $this->rows[$rowNo][$y], $output);
				$value .= $output ."<br />";
			}
		} else {
			$output = $this->rows[$rowNo][$fieldNo];
		}
		// return the new value
		return $output;
	}
	// set up the field format
	function fieldFormat($fieldNo, $format){
		// add the field format to the fieldFormats array
		$this->fieldFormats[$fieldNo] = $format;
	}
	
	// show the header row
	function showHeader(){
		$header = "";
		// print the header row
		$header .= "	<tr>\n";
		// loop the fields
		foreach ($this->fields as $field) {
			// print each field
			$header .= "		<th>".$field."</th>\n";
		}
		// end the header row
		$header .= "	</tr>\n";
		return $header;
	}
	
	// show the data table
	function showDataTable(){
		$output = "";
		// print the table
		$output .= "<table summary=\"".$this->summary."\">\n";
		// print the caption
		$output .= "<caption>".$this->caption."</caption>\n";
		$output .= $this->showHeader();
		// initialise variables
		$altCounter = 0;
		$altClass = "";
		$h = 1;
		// loop each row
		for ($x=0; $x<count($this->rows); $x++) {
			// if it is time to show the header
			if ($h==$this->headerRepeat){
				// show the header
				$output .= $this->showHeader();
				$h = 1;
			}
			$row = $this->rows[$x];
			// alternate the row classes
			if ($this->altClasses){
				if ($this->altClasses[$altCounter]!=""){ $altClass = " class=\"".$this->altClasses[$altCounter]."\""; } else { $altClass=""; }
				if ($altCounter==count($this->altClasses)-1){ $altCounter=0; } else { $altCounter++; }
			}
			// set the parameters to nothing
			$params = "";
			// if there are parameters for this row set
			if (count($this->rowParams[$x])>0){
				// loop the parameters
				while (list($attribute, $parameter) = each($this->rowParams[$x])) {
					// if the parameter is 'class'
					if (strtolower($attribute)=="class"){
						// replace the altClass variable
						$altClass = " ".strtolower($attribute)."=\"$parameter\"";
					} else{
						// otherwise build the parameters
						$params .= " ".strtolower($attribute)."=\"$parameter\"";
					}
				}
			}
			// print the row
			$output .= "	<tr$altClass$params>\n";
				// set the colSpan to 0
				$colSpan = 0;
				$colSpanAttribute = "";
				// if this row has less columns than the number of fields
				if (count($row)<count($this->fields)){
					$colSpan = (count($this->fields)-count($row))+1;
				}
				// loop each cell
				for ($i=0; $i<count($row); $i++) {
					$value = $row[$i];
					$value = $this->formatField($i, $x);
					// make the colspan attribute
					if ($colSpan>0 && $i==(count($row)-1)){ $colSpanAttribute = " colspan=\"$colSpan\""; }
					// print the cell
					$output .= "		<td$colSpanAttribute>".$value."</td>\n";
				}
			// end the row
			$output .= "	</tr>\n";
			// increment the header repeat variable
			$h++;
		}
		// end the table
		$output .= "</table>\n\n";
		print $output;
	}
}

?>

Future developments: I’m working on a ‘dataBind’ method (you can see it in the script above, actually) that will allow the almost-instant binding of a MySQL recordset to a table, saving you the hassle of doing all that pesky looping malarkey. Hopefully it will be done soon.

Leave a Reply