Please give comments to the table class I created. It definitely needs some improvement, but I am guessing it is quite useful to construct simple tables, especially for tables used to show database results:

The class file:

<?php

class Table {
  public $tablename;
  public $columns = array();
  public $columnwidth;
  public $tablewidth;
  public $style;
  public $alignment;
  public $cells = array();
  public $background = array();
  public $content;

  public function __construct($tablename, $columns, $columnwidth = "", $tablewidth = "", $background = ""){
      // Create the table
	  $this->tablename = $tablename;
	  if(!is_array($columns)) die("Cannot create a table with only one column...");
	  if(is_array($columnwidth) and count($columns) != count($columnwidth)) die("Specification of column width is incorrect, please report this to administrator.");
      $this->columns = $columns;
	  if(is_array($columnwidth)){
         foreach($columnwidth as $width){
	        $this->columnwidth[] = "width='{$width}'";
	     }
      }
      elseif(!empty($columnwidth) and !is_array($columnwidth)) $this->columnwidth = " width='{$columnwidth}'";
      else $this->columnwidth = "";	  
$this->tablewidth = $tablewidth; $this->background = $background; $this->content = "<br>"; } public function createtable($alignment = "", $style = "", $border = "yes"){ // This method builds the interface of the table, it must be chained with showtable() or buildtable() $this->alignment = $alignment; $this->style = $style; $this->columns = $this->formattable($this->columns); // Construct the basic table structure $this->content .= "</br><table"; $this->content .= (!empty($this->tablewidth))?" width='{$this->width}'":""; $this->content .= ($border == "yes")?" border='1'":""; $this->content .= (!empty($this->background))?" {$this->background[0]}='{$this->background[1]}'>":">"; // Create the very first row of table $i = 0; $this->content .= "<tr>"; foreach($this->columns as $column){ $this->content .= (is_array($this->columnwidth))?"<td {$this->columnwidth[$i]}>{$column}</td>":"<td {$this->columnwidth}>{$column}</td>"; $i++; } $this->content .= "</tr>"; return $this; } public function buildtable($cells, $alignment = "", $style = ""){ // This method will build the body of our table, it must be chained with showtable() or endtable() $this->content .= "<tr>";
$this->alignment = (!empty($alignment))?$alignment:$this->alignment; $this->style = (!empty($style))?$style:$this->style; $this->cells = $this->formattable($cells); // Now it is time to construct a row of our table $i = 0; foreach($this->cells as $cell){ $this->content .= "<td>{$cell}</td>"; $i++; } $this->content .= "</tr>"; return $this; } private function formattable($text){ // Thie method formats the content of tables with alignment or style, can only be called witin the table class if(!is_array($text)) die("Cannot format the table content."); if(!empty($this->style)){ if(is_array($this->style) and count($this->style) != count($text)) die("Cannot specify the style of table columns..."); for($i = 0; $i < count($text); $i++){ $text[$i] = (is_array($this->style))?"<{$this->style[$i]}>{$text[$i]}</{$this->style[$i]}>":"<{$this->style}>{$text[$i]}</{$this->style}>"; } } if(!empty($this->alignment)){ if(is_array($this->alignment) and count($this->alignment) != count($text)) die("Cannot specify alignment of table columns..."); for($i = 0; $i < count($text); $i++){ $text[$i] = (is_array($this->alignment))?"<{$this->alignment[$i]}>{$text[$i]}</{$this->alignment[$i]}>":"<{$this->alignment}>{$text[$i]}</{$this->alignment}>"; } } return $text; } public function showtable(){ // This method allows the page to show an unfinished table, incase control blocks, loops or forms need to be used $content = $this->content; unset($this->content); return $content; } public function endtable(){ // This method terminates the construction of a table $this->content .= "</table>"; return $this->content; } } ?>

Here is an example:

<?php

include("classes/class_tables.php");

$content = "";

$table = new Table("Mytable", array("Column1", "Column2", "Column3", "Column4"), 100, 400, array("bgcolor", "#FFA500"));
$content .= $table->createtable("left")->showtable();
$content .= $table->buildtable(array("r1c1","r1c2","r1c3","r1c4"), "center", "strong")->showtable();
$content .= $table->buildtable(array("r2c1", "r2c2", "r2c3", "r2c4"), "left", "u")
                  ->buildtable(array("r3c1", "r3c2", "r3c3", "r3c4"), "center", "li")
                  ->showtable();
$content .= $table->buildtable(array("r4c1", "r4c2", "r4c3", "r4c4"), "left", "strike")->endtable();

echo $content;
?>

The example gives a table that looks like this:
http://oi41.tinypic.com/2gt4yvl.jpg

So what do you think? Please do not hesitate to point out any problems you see from the codes, Id like to improve it as much as I can before using it in the applications of mine. Comments please?

    Actually I was going to comment that it might be useful to abstract the table building a bit further to general document building. Then a table class that has a document builder property for the lower-level stuff, and concentrates itself on the table-specific stuff. Two directions for extension offer themselves then: with a different document builder, this same class can write tables for other situations; and with the same document builder, a Form class can write forms.

    Looking at your style, a typical document builder method might have a signature like

    DocumentBuilder startelement(string $tagname, [array($name=>$value)]);
    

    So to start an element you pass the name ("table" and optionally an array of name/value pairs for the attributes, and the DocumentBuilder object will append a "<table foo='bar'> to its string content. The method finishes by returning $this, for chaining.

    There would be a corresponding endelement() method that takes an optional tag name. If a name is not supplied, the most recent open tag is closed (the document builder will need to keep a stack). If a name is supplied, it has to match some currently-open tag on the stack or it's an error. Assuming it's there, therefore, the document build pops the stack and appends closing tags until it finds one that matches.

    There may also be empty elements; just an "element($tagname, [array($name=>$value)])".

    And text. And maybe also other document builders.

    And, finally, a "content()" method which returns the string built up. I'm in two minds whether this should close any tags that happen to remain open.

    function createtable($alignment = '', $style = '', $border = 'yes')
    {
    	$this->alignment = $alignment;
    	$this->style = $style;
    	$this->columns = $this->formattable($this->columns);
    	$table_properties = array();
    	if(!empty($this->tablewidth))
    	{
    		$table_properties['width'] = $this->wdith;
    	}
    	if($border == 'yes')
    	{
    		$table_properties['border'] = 1;
    	}
    	if(!empty($this->background))
    	{
    		$table_properties[$this->background[0]] = $this->background[1];
    	{
    	$this->content->element('br')
    		->startelement('table', $table_properties)
    		->startelement('tr');
    	if(is_array($this->columnwidth))
    	{
    		$i = 0;
    		foreach($this->columns as $column)
    		{
    			$this->content->startelement('th', array('width'=>$this->column_width[$i++]))->add($column)->endelement();
    		}
    	}
    	else
    	{
    		foreach($this->columns as $column)
    		{
    			$this->content->startelement('th', array('width'=>$this->column_width))->add($column)->endelement();
    		}
    	}
    	$this->content->endelement('tr');
    	return $this;
    }
    
    function buildtable($cells, $alignment = '', $style = '')
    {
    	if(!empty($alignment)
    		$this->alignment = $alignment;
    	if(!empty($style))
    		$this->style = $style;
    	$this->content->startelement('tr');
    	foreach($this->cells as $cell)
    	{
    		$this->content->startelement('td')->add($cell)->endelement();
    	$this->content->endelement('tr');
    	return $this;
    }
    

      It might be interesting to take a look at http://pear.php.net/package/HTML_Table to compare its methods and their signatures in order to see if there is anything different in their approach that you might like to incorporate or that gives you ideas for improvements.

        @:
        Interesting comments, thank you so much for the input. I thought I was never gonna get any feedback... I dont mind getting seriously criticized for making a poorly-designed script though, all I need to know is how I can improve it.

        I think an abstract strategy will work out nicely, so yeah I agree with you. I do plan to create a form class and even an iframe class, guess it can save me troubles in future. I was also thinking about designing a page class with page title and content being static properties. Not sure if it is a decent idea though, lemme know if it is not so I can dump bad ideas before getting started.

        At this point I have created a function called getattributes() in the core functions file, which returns attributes of tables, forms and other elements from database. Since my software has an admin control panel, Id say it is a feasible idea giving admins enough control over their preference regarding default html document settings.

        The class Table has also been revised, it looks a bit more complicated but I hope I've at least improved it a bit. Would you mind taking a look again and lemme know what you think? I have not done it in an abstract design pattern yet, but guess I will choose this path and edit the codes again a few days later:

        <?php
        
        class Table {
          public $tablename; 
          private $columns = array();
          private $columnwidth;
          private $attributes;
          private $cells = array();  
        private $pointer = 0; private $header = ""; private $body = array(); private $footer = ""; public function __construct($tablename, $columns, $columnwidth = "", $attributes = ""){ // Create the table if(!is_array($columns)) die("Cannot create a table with only one column..."); if(is_array($columnwidth) and count($columns) != count($columnwidth)) die("Specification of column width is incorrect, please report this to administrator."); $this->columns = $columns; if(is_array($columnwidth)){ foreach($columnwidth as $width){ $this->columnwidth[] = "width='{$width}'"; } } elseif(!empty($columnwidth) and !is_array($columnwidth)) $this->columnwidth = " width='{$columnwidth}'"; else $this->columnwidth = ""; // Initiate the header with table attributes information $this->attributes = (!empty($attributes))?$attributes:getattributes()->table; $this->header = "<br><table"; $this->header .= (!empty($this->attributes->width))?" width='{$this->attributes->width}'":""; $this->header .= (!empty($this->attributes->border))?" border='{$this->attributes->border}'":""; $this->header .= (is_numeric($this->attributes->cellpadding))?" cellpadding='{$this->attributes->cellpadding}'":""; $this->header .= (is_numeric($this->attributes->cellspacing))?" cellspacing='{$this->attributes->cellspacing}'":""; $this->header .= (!empty($this->attributes->frame))?" frame='{$this->attributes->frame}'":""; $this->header .= (!empty($this->attributes->rules))?" rules='{$this->attributes->rules}'":""; $this->header .= (!empty($this->attributes->summary))?" summary='{$this->attributes->summary}'":""; $this->header .= (!empty($this->attributes->background))?" {$this->attributes->background[0]}='{$this->attributes->background[1]}'>":">"; } public static function setattributes($attributes, $values){ // This method allows us to modify default table attributes anywhere inside the script, it can be called with or without instantiating a table object. if(!is_array($values)) die("Cannot set table attributes without any inputs..."); foreach($values as $key => $val){ $attributes->$key = $val; } return $attributes; } public function getheader($align = "", $style = ""){ // This method allows the page to show an unfinished table, incase control blocks, loops or forms need to be used $this->attributes->align = (!empty($align))?$align:$this->attributes->align; $this->attributes->style = (!empty($style))?$style:$this->attributes->style; $this->columns = $this->formattable($this->columns); $i = 0; $this->header .= "<tr>"; foreach($this->columns as $column){ $this->header .= (is_array($this->columnwidth))?"<th {$this->columnwidth[$i]}>{$column}</th>":"<th {$this->columnwidth}>{$column}</th>"; $i++; } $this->header .= "</tr>"; return $this->header; } public function buildtable($cells, $align = "", $style = ""){ // This method will build the body of our table, needs to be chained with showtable() or endtable() $index = count($this->body); $this->body[$index] .= "<tr>";
        $this->attributes->align = (!empty($align))?$align:$this->attributes->align; $this->attributes->style = (!empty($style))?$style:$this->attributes->style; $this->cells = $this->formattable($cells); // Now it is time to construct a row of our table $i = 0; foreach($this->cells as $cell){ $this->body[$index] .= "<td>{$cell}</td>"; $i++; } $this->body[$index] .= "</tr>"; return $this; } private function formattable($text){ // Thie method formats the content of tables with alignment or style, can only be called witin the table class if(!is_array($text)) die("Cannot format the table content."); if(!empty($this->attributes->style)){ if(is_array($this->attributes->style) and count($this->attributes->style) != count($text)) die("Cannot specify the style of table columns..."); for($i = 0; $i < count($text); $i++){ $text[$i] = (is_array($this->attributes->style))?"<{$this->attributes->style[$i]}>{$text[$i]}</{$this->attributes->style[$i]}>":"<{$this->attributes->style}>{$text[$i]}</{$this->attributes->style}>"; } } if(!empty($this->attributes->align)){ if(is_array($this->attributes->align) and count($this->attributes->align) != count($text)) die("Cannot specify alignment of table columns..."); for($i = 0; $i < count($text); $i++){ $text[$i] = (is_array($this->attributes->align))?"<{$this->attributes->align[$i]}>{$text[$i]}</{$this->attributes->align[$i]}>":"<{$this->attributes->align}>{$text[$i]}</{$this->attributes->align}>"; } } return $text; } public function resetpointer($index = 0){ // This method allows the page to show an unfinished table, incase control blocks, loops or forms need to be used if(!is_int($index)) die("The index must be zero or a positive integer"); elseif($this->pointer < $index) die("Failed to reset pointer..."); else $this->pointer = $index; } public function showtable($showheader = "no"){ // This method allows the page to show an unfinished table, incase control blocks, loops or forms need to be used $content = ($showheader == "yes")?$this->header:""; if(empty($this->body[$this->pointer])) die("The table has no more content to show..."); for($i = $this->pointer; $i < count($this->body); $i++){ $content .= $this->body[$this->pointer]; $this->pointer++; } return $content; } public function endtable(){ $content = ""; // This method terminates the construction of a table if(!empty($this->footer)) die("The table has already ended..."); for($i = $this->pointer; $i < count($this->body); $i++){ $content .= $this->body[$this->pointer]; $this->pointer++; } $this->footer = "</table>"; $content .= $this->footer; return $content; } } ?>

        @:
        Thanks for your comment. And yeah I've looked into that already, it inspired me a bit on my latest revision of this table class.

          My comment would be to use user_error / trigger_error or throwing exceptions instead of using die when things are wrong. Die will completely halt your script, and not give you a chance to handle the errors more gracefully.

            Derokorian;11000435 wrote:

            My comment would be to use user_error / trigger_error or throwing exceptions instead of using die when things are wrong. Die will completely halt your script, and not give you a chance to handle the errors more gracefully.

            Thanks for the comment and yeah I agree with you on this point. I may be defining all system messages as variables or constants stored in a script file called $lang.php, or even mysql database so that people wont see this many hard-coded strings in class files.

              Write a Reply...