Helpful Information
 
 
Category: Post a PHP snippet
Basic Table Class

Let me preface this with, this is only the second php class I've ever written so be gentle ;) But it would be nice to hear what some of you pros think about it ;)

This is a set of classes for drawing html tables (I hate typing up html)


<?
class table
{
var $width;
var $class;
var $id;
var $style;
var $summary;
var $rows = array();
var $attributes = array();
var $setAttributes;

function table($width = "", $class = "", $id = "", $style = "", $summary = "")
{
$this->width = $width;
$this->class = $class;
$this->id = $id;
$this->style = $style;
$this->summary = $summary;
}

function addRow($class = "", $id = "", $placement = "body", $valign = "")
{
$row = new row;
$row->class = $class;
$row->id = $id;
$row->placement = $placement;
$row->valign = $valign;
$this->rows[] = $row;
}

function getSetAttributes($attributes)
{
foreach($attributes as $attribute)
{
if(!empty($this->$attribute))
{
$this->attributes[] = $attribute;
}
}
foreach($this->attributes as $attribute)
{
$this->setAttributes.=" ".strtolower($attribute)." = \"".$this->$attribute."\"";
}
}

function draw()
{
$this->getSetAttributes(array("width", "class", "id", "style", "summary"));
$output.= "<table ".$this->setAttributes.">\n";
$placements = array("head", "body", "foot");
foreach($placements as $placement)
{
$output2 = "";
foreach($this->rows as $row)
{
if($row->placement == $placement)
{
$output2.=$row->draw();
}
}
if(!empty($output2))
{
$output .="\t<t$placement>\n";
$output .=$output2;
$output .="\t</t$placement>\n";
}
}
$output.="</table>\n";
echo $output;
}

}

class row extends table
{
var $valign;
var $placement;
var $cells = array();

function addCell($content, $type = "d", $class = "", $id = "", $rowspan = "", $colspan = "", $valign ="", $scope = "")
{
$cell = new cell;
$cell->content = $content;
$cell->type = $type;
$cell->class = $class;
$cell->id = $id;
$cell->rowspan = $rowspan;
$cell->colspan = $colspan;
$cell->valign = $valign;
$cell->scope = $scope;
$this->cells[]= $cell;
}

function draw()
{
table::getSetAttributes(array("class", "id", "valign"));
$output .= "\t\t<tr ".$this->setAttributes.">\n";
foreach($this->cells as $cell)
{
$output.=$cell->draw();
}
$output.="\t\t</tr>\n";
return $output;
}
}

class cell extends row
{
var $type;
var $rowspan;
var $colspan;
var $scope;
var $content;

function draw()
{
table::getSetAttributes(array("class", "id", "rowspan", "colspan", "valign", "scope"));
$output = "\t\t\t<t".$this->type." ".$this->setAttributes.">".$this->content."</t".$this->type.">\n";
return $output;
}
}
?>


example usage:


$table = new table;
$table->addRow("", "", "head");
$table->rows[0]->addCell("Name", "h");
$table->rows[0]->addCell("fred");
$table->rows[0]->addCell("bob");
$table->draw();


outputs


<table >
<thead>
<tr >
<th >Name</th>
<td >fred</td>
<td >bob</td>

</tr> </thead>
<tbody>
</tbody>
<tfoot>
</tfoot>
</table>

I haven't tested the code itself but I think you have an OO logic error in your structure. When a class extends another class it should be a logical member of that class. For example if you have a class 'shape' it can be extended by 'circle' or 'square' because they are shapes. Here you're extending 'table' by 'row', which is like extending 'shape' by 'point', likewise 'row' by 'cell'. A row is not a table and a cell is not a row; they're not extensions but substituents.

If they need to share methods they should implement a common interface, not extend eachother.

clarity edit:
Image you have a class 'car.' You can extend it by Audi because Audis are cars and they have certain extensions to the base definition of car, like, say, the Olympic looking Audi logo and default silver color. What you are doing is akin to extending car with engine, and then extending engine with piston. They're related, but 'engine' does not extend 'car' because extensions inherit all functionality from their parents. Anything that extends car, and anything that extends table, must have all properties common to car and table, respectively.

The reason is that, later, a perfectly reasonable developer may pick up the car class and decide to add the method getAdjustableSeatParams() to return how far back the seats go, for the benefit of larger drivers. The developer correctly assumes that this method must be applicable to any class that extends car, but engine->getAdjustableSeatParams() makes no sense. Audi->getAdjustableSeatParams() does. Your classes already exhibit an inheritance problem: class row inherits addRow() even though in the subclassed context it makes no sense.

I'd probably like it better if this is how it could be written as what I've shown below, although it's not very pretty but I partially blame that on my own dislike for php's syntax.

$table = new Table;
$attribs = array('class' => 'my_class', 'id' => 'my_id');
$tr = Table::create_row($attribs);

$td_stub = Table::create_cell($attribs);
/* could be modified to do
$td_stub = Table::create_cell($attribs, $value_here_instead); */

$td_1 = $td_stub;
$td_1->set_value('string');
$td_2 = $td_stub;
$td_2->set_value('string');
$td_3 = $td_stub;
$td_3->set_value('string');

$tr->set_cols(array( $td_1, $td_2, $td_3));

$table->add_row($tr);

$table->draw();

If they need to share methods they should implement a common interface, not extend eachother.


Care to elaborate how I might achieve this?

I aggree with your point about the inheritance not being 100% logical but it is more efficient.
I started out with individual classes for table, row and cell but that ended up with a lot of repeated code, given that PHP OOP is vastly inefficient to begin with, I decided it would be far neater to do it this way. If there is another way to acheive the same effect without 'illogical' inheritance, I'd be happy to hear it.

I think it's a pretty cool script :)

I found myself doing repeated jazz like that for all of my asp reports. So awhile back I made almost the exact same class, but in asp.

Care to elaborate how I might achieve this?

Interfaces won't actually save you any repetition, but you could make all the classes extend a new, more abstracted parent like 'HTMLTableElement' that contains their shared methods and variables. Or you could leave it just like it is; I was just making what I intended as a helpful comment but may have come across a bit pedantic :(

Slight pedantism, but the order of 'placements' should be head,foot,body.

As for structure, being able to do something like the following would make the most sense to me:
$table = new table();
$row1=$table->addRow(); //returns a row object or false
$cell1=$row1->addCell(); //returns a cell object or false
etc.










privacy (GDPR)