|
Posted by Steve on 11/10/06 00:36
create file called report.class.php and paste this into it. fix text
wrapping.
======================
<?
class reportColumn
{
var $alias = '';
var $format = '%s';
var $name = '';
var $type = 'string';
var $values = array();
function reportColumn(
$name ,
$alias = '' ,
$type = 'string' ,
$format = '%s'
)
{
if ($alias == ''){ $alias = $name; }
$this->alias = $alias;
$this->format = $format;
$this->name = $name;
$this->type = $type;
}
}
class reportCriteria
{
var $comparison = array();
var $evaluation = '=';
var $source = '';
function reportCriteria($source, $evaluation, $comparison)
{
if (!is_array($comparison)){ $comparison = array($comparison); }
$this->comparison = $comparison;
$this->evaluation = $evaluation;
$this->source = $source;
}
}
class reportFormula
{
var $column = '';
var $criteria = array();
var $format = '%s';
var $formula = '';
var $literal = false;
var $name = '';
var $recordCount = 0;
var $result;
function reportFormula(
$name ,
$column ,
$formula ,
$criteria = array() ,
$format = '%s'
)
{
$this->column = $column;
$this->criteria = $criteria;
$this->format = $format;
$this->formula = $formula;
$this->literal = !ereg('^{([^}]*)}$', $name);
$this->name = $name;
}
}
class reportFormulaResult
{
var $average = 0;
var $count = 0;
var $percent = 0;
var $sample = 0;
var $sum = 0;
function reportFormulaResult(){}
}
class reportFormulaResultSubGroup
{
var $average = 0;
var $count = 0;
var $percent = 0;
var $sum = 0;
function reportFormulaResultSubGroup(){}
}
class reportGroup
{
var $keys = array();
var $name = '';
var $subGroups;
var $total = 0;
function reportGroup($name){ $this->name = $name; }
}
class reportGrouping
{
var $name = '';
var $subGroups;
var $total = 0;
function reportGrouping($name){ $this->name = $name; }
}
class reportSubGroup
{
var $keys = array();
var $name = '';
var $parent = '';
var $subGroups;
var $total = 0;
var $value = '';
function reportSubGroup($name){ $this->name = $name; }
}
class reportSummary
{
var $formulas = array();
var $name = '';
function reportSummary($name, $formulas)
{
if (!is_array($formulas)){ $formulas = array($formulas); }
$this->name = $name;
foreach ($formulas as $formula)
{
$this->formulas[] = new reportFormula(
$formula->name ,
$formula->column ,
$formula->formula ,
$formula->criteria ,
$formula->format
);
}
}
}
class report
{
var $title = '';
var $columns = array();
var $display = array();
var $groupings = array();
var $immediate = true;
var $recordCount = 0;
var $records = array();
var $summary = array();
var $tree = array();
function report(
$title,
$records,
$display = array(),
$groupBy = array(),
$summary = array(),
$total = array()
)
{
if (!is_array($display)){ $display = array($display); }
if (!is_array($groupBy)){ $groupBy = array($groupBy); }
if (!is_array($records)){ $records = array($records); }
if (!is_array($summary)){ $summary = array($summary); }
if (!is_array($total)){ $total = array($total); }
$this->recordCount = count($records);
$this->records = $records;
$this->summary = $summary;
$this->title = $title;
foreach ($records as $record => $columns)
{
foreach ($columns as $column => $value)
{
if (!isset($this->columns[$column]))
{
$this->columns[$column] = new reportColumn($column);
}
$this->columns[$column]->values[] = $value;
}
}
foreach ($display as $column)
{
$this->display[$column->name] = $column;
$this->columns[$column->name]->alias = $column->alias;
$this->columns[$column->name]->format = $column->format;
$this->columns[$column->name]->type = $column->type;
}
if (count($groupBy) == 0){ return; }
foreach ($groupBy as $column)
{
$column = $this->columns[$column];
if (!isset($column)){ continue; }
$grouping = new reportGrouping($column->name);
$grouping->subGroups = new reportGroup($column->name);
$grouping->total = isset($total[$column->name]) ?
$total[$column->name] : false;
$this->groupings[] = $grouping;
$values = array();
foreach ($column->values as $key => $value)
{
$values[$value]->total++;
$values[$value]->keys[] = $key;
$grouping->subGroups->keys[] += $key;
}
$grouping->subGroups->keys =
array_unique($grouping->subGroups->keys);
foreach ($values as $value => $properties)
{
$subGroup = new
reportSubGroup($column->name);
$subGroup->keys = $properties->keys;
$subGroup->total = $properties->total;
$subGroup->value = $value;
$grouping->subGroups->subGroups[] = $subGroup;
$grouping->subGroups->total += $subGroup->total;
}
}
$groupCount = count($this->groupings);
if ($groupCount == 0){ return; }
$branches[] = $this->groupings[0]->subGroups->subGroups;
for ($i = 1; $i < $groupCount; $i++)
{
$branches[] = $this->_getGrouping(
$this->groupings[$i]->subGroups->subGroups,
$branches[$i - 1]
);
}
for ($i = 1; $i < $groupCount; $i++)
{
$nests = $branches[$i];
$tree = $branches[$i - 1];
foreach ($tree as $branch)
{
foreach ($nests as $nest)
{
if ($nest->parent != $branch->value){ continue; }
$branch->subGroups[] = $nest;
}
}
}
for ($i = 0; $i < $groupCount; $i++)
{
$this->groupings[$i]->subGroups = $branches[$i];
}
$this->tree = $branches[0];
}
function _getGrouping($branches, $limbs = array())
{
foreach ($limbs as $key => $limb)
{
foreach ($branches as $branch)
{
$nest = array_intersect($branch->keys,
$limb->keys);
if (empty($nest)){ continue; }
$subGroup = new reportSubGroup($branch->name);
$subGroup->keys = $nest;
$subGroup->parent = $limb->value;
$subGroup->total = count($nest);
$subGroup->value = $branch->value;
$subGroups[] = $subGroup;
}
}
return $subGroups;
}
function _evaluate($value, $evaluation, $array)
{
if (!is_array($array)){ $array = array($array); }
$truth = in_array($value, $array);
switch ($evaluation)
{
case '=' : return $truth; break;
case '!=' : return !$truth; break;
case '<' :
case '>' : $truth = count($array) ? true : false;
foreach ($array as $comparison)
{
if ($comparison == '<' && $truth){ $truth = $value
< $comparison; }
if ($comparison == '>' && $truth){ $truth = $value
> $comparison; }
}
return $truth;
break;
case 'BETWEEN' : $truth = count($array) ? true : false;
foreach ($array as $comparison)
{
$min = isset($min) ? min($min, $comparison) : $min
= $comparison;
$max = isset($max) ? min($max, $comparison) : $max
= $comparison;
}
return $value >= $min && $value <= $max;
break;
default : return false;
}
return false;
}
function _getHTML($branch)
{
$html = '';
if (is_array($branch))
{
foreach ($branch as $nest)
{
$html .= $this->_getHTML($nest) . '<br/>';
}
return $html;
}
$summary = "
<table cellpadding='0px' cellspacing='0px' class='reportTable'
<tr class='reportHeader' style='text-align:right;'>
<td class='reportHeader' style='width:150px'>
" . $branch->value . "
</td>
<td class='reportCell' style='text-align:right;width:75px'>
<b>" . $branch->total . " </b>
</td>
</tr>
</table>
";
if (count($branch->subGroups) != 0)
{
foreach ($branch->subGroups as $nest)
{
$html .= $this->_getHTML($nest) . '<br/>';
}
return '<br/>' . $summary . '<br/>' . $html . $summary;
}
$html .= "
<table cellpadding='0px' cellspacing='0px' class='reportTable'
";
$html .= "
<tr class='reportHeader'>
";
foreach ($this->display as $column)
{
$html .= "
<td class='reportHeader' style='text-align:right'>
" . $column->alias . "
</td>
";
}
$html .= "
</tr>
";
foreach ($branch->keys as $record)
{
$html .= "
<tr class='reportRow'>
";
foreach ($this->display as $column)
{
$html .= "
<td class='reportCell'>
" . $this->records[$record][$column->name] . "
</td>
";
}
$html .= "
</tr>
";
}
$html .= "
</table>
";
return $summary . $html . $summary;
}
function _getId()
{
return strtoupper(md5(uniqid(rand(), true)));
}
function _getSummaries($keys = array())
{
$filter = count($keys) ? true : false;
$reportSummaries = array();
$compactSummary = array();
$recordCount = $filter ? count($keys) : $this->recordCount;
if (count($this->summary) == 0){ return false; }
$formulas = array();
foreach ($this->summary as $reportSummary)
{
foreach ($reportSummary->formulas as $key => $formula)
{
$reportSummaries[$reportSummary->name][$formula->column][$formula->formula][]
= $formula;
}
}
if ($filter)
{
return $reportSummaries; // not yet implemented
}
foreach ($reportSummaries as $sectionName => $columns)
{
foreach ($columns as $column => $operations)
{
foreach ($operations as $operation => $formulas)
{
foreach ($formulas as $formula)
{
$processedFormula = $this->_processFormula($formula);
$compactSummary[$sectionName][$formula->name][] =
$processedFormula;
}
}
}
}
foreach ($compactSummary as $columns)
{
foreach ($columns as $formulas)
{
foreach ($formulas as $formula)
{
$operation = $formula->formula;
if ($operation == 'AVERAGE')
{
if ($formula->result->average != 0)
{
$formula->result->average = $formula->recordCount /
$formula->result->average;
}
}
if ($operation == 'PERCENT')
{
if ($formula->recordCount != 0)
{
$formula->result->percent = ($formula->result->percent /
$formula->recordCount) * 100;
}
}
if (!count($formula->subGroups)){ continue; }
foreach ($formula->subGroups as $subGroup)
{
if ($operation == 'AVERAGE')
{
if ($subGroup->average != 0)
{
$subGroup->average = $formula->recordCount /
$subGroup->average;
continue;
}
}
if ($operation == 'PERCENT')
{
if ($formula->recordCount != 0)
{
$subGroup->percent = ($subGroup->percent /
$formula->recordCount) * 100;
}
}
}
}
}
}
return $compactSummary;
}
function _processFormula($formula)
{
$column = $formula->column;
$literal = $formula->literal;
$records = $this->records;
$source = $formula->criteria->source;
$type = $this->columns[$column]->type;
for ($i = 0; $i < $this->recordCount; $i++)
{
$key = $records[$i][$column];
$result = $formula->result;
$value = $key;
if (!isset($result))
{
$result = new reportFormulaResult();
$formula->result = $result;
}
$truth = true;
if (count(($criteria = $formula->criteria)))
{
$truth = $this->_evaluate(
$records[$i][$source] ,
$criteria->evaluation ,
$criteria->comparison
);
}
if ($type == 'string'){ $value = 1; }
switch ($formula->formula)
{
case 'AVERAGE' : $result->average += $truth ? $value : 0;
break;
case 'COUNT' : $result->count++;
break;
case 'PERCENT' : $result->percent += $truth ? $value : 0;
break;
case 'SUM' : $result->sum += $truth ? $value : 0;
break;
default : break;
}
$formula->recordCount += $value;
}
for ($i = 0; $i < $this->recordCount; $i++)
{
$truth = true;
$value = $records[$i][$column];
if (count(($criteria = $formula->criteria)))
{
$truth = $this->_evaluate(
$records[$i][$source] ,
$criteria->evaluation ,
$criteria->comparison
);
if (!$truth){ continue; }
}
$subGroup = $formula->subGroups[$value];
if (!isset($subGroup))
{
$subGroup = new reportFormulaResultSubGroup();
$formula->subGroups[$value] = $subGroup;
}
$value = $records[$i][$formula->column];
if ($type == 'string'){ $value = 1; }
switch ($formula->formula)
{
case 'AVERAGE' : $subGroup->average += $truth ? $value : 0;
break;
case 'COUNT' : $subGroup->count++;
break;
case 'PERCENT' : $subGroup->percent += $truth ? $value : 0;
break;
case 'SUM' : $subGroup->sum += $truth ? $value : 0;
break;
default : break;
}
}
ksort($formula->subGroups);
reset($formula->subGroups);
return $formula;
}
function _showStatus($index)
{
if (!$this->immediate){ return; }
$status = '
<script language="javascript1.2" type="text/javascript">
showStatus(' . (($index / $this->recordCount) * 100) . ');
</script>
';
print $status;
}
function toCSV()
{
$csv = '';
foreach ($this->records as $record => $columns)
{
foreach ($this->display as $column)
{
$value = htmlspecialchars($columns[$column->name]);
$csv .= "\"$value\", ";
}
$csv = substr($csv, 0, - 2) . "\r\n";
}
return $csv;
}
function toHTML($immediate = true)
{
$reportDate = date('m/d/Y H:i:s');
$reportId = $this->_getId();
$this->immediate = $immediate;
$html = '
<script language="javascript1.2" type="text/javascript">
function showStatus(percent)
{
b = document.getElementById("reportProgressBar");
f = document.getElementById("reportCurrentProgress");
var width = parseInt(b.style.width);
var percent = parseInt(percent);
width = (percent * width) / 100;
f.style.width = width + "px";
}
</script>
<style type="text/css">
@media print
{
@page
{
@bottom-left
{
content : "Report ID ' . $reportId . '" ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 10pt ;
font-weight : normal ;
text-align : left ;
}
@bottom-right
{
content : "Page " counter(pages) ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 10pt ;
font-weight : normal ;
text-align : left ;
}
@top-left
{
content : "' . $this->title . '" ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 12pt ;
font-weight : bolder ;
text-align : left ;
}
@top-right
{
content : "' . $reportDate . '" ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 12pt ;
font-weight : bolder ;
text-align : left ;
}
counter-increment : pages ;
margin : 0.25in ;
.nonPrinting
{
display : none ;
}
.reportTable
{
page-break-inside : avoid ;
}
}
}
@media
{
.pageBreak
{
page-break-after : always ;
}
.reportCell
{
background-color : white ;
border-bottom : solid 1px lightsteelblue ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 8pt ;
font-weight : normal ;
overflow : visible ;
text-align : right ;
white-space : nowrap ;
width : 100px ;
}
.reportHeader
{
background-color : ghostwhite ;
border-bottom : solid 1px lightsteelblue ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 8pt ;
font-weight : bold ;
text-align : left ;
white-space : nowrap ;
width : 100px ;
}
.reportProgressBar
{
background-color : lightsteelblue ;
border : solid gray 1px ;
width : 550px ;
}
.reportCurrentProgress
{
background-color : lime-green ;
border : solid gray 1px ;
width : 0px ;
}
.reportRow
{
background-color : ghostwhite ;
font-family : arial ,
verdana ,
tahoma ,
sans-serif ;
font-size : 10pt ;
font-weight : normal ;
overflow : visible ;
text-align : left ;
white-space : nowrap ;
width : 100px ;
}
.reportTable
{
background-color : white ;
border : solid 1px lightsteelblue ;
margin : 2px ;
}
}
</style>
<div class="nonPrinting" style="display:none;">
<div class="reportRow">Creating...' . $pageTitle . '</div>
<div class="reportProgressBar" id="reportProgressBar">
<span class="reportCurrentProgress"
id="reportCurrentProgress"></span>
</div>
</div>
';
$header = "
<table cellpadding='0px' cellspacing='0px' class='reportTable'>
<tr class='reportRow'>
<td class='reportHeader' style='font-size:6pt;'>NAME</td>
<td class='reportHeader'
style='font-size:6pt;text-align:right; width:225px;'>
" . $this->title . "
</td>
</tr>
<tr class='reportRow'>
<td class='reportHeader' style='font-size:6pt;'>REPORT ID</td>
<td class='reportHeader'
style='font-size:6pt;text-align:right; width:225px;'>
" . $reportId . "
</td>
</tr>
<tr class='reportRow'>
<td class='reportHeader' style='font-size:6pt;'>DATE</td>
<td class='reportHeader'
style='font-size:6pt;text-align:right; width:225px;'>
" . $reportDate . "
</td>
</tr>
</table>
<br/>
<br/>
";
if ($this->immediate)
{
print $html;
$html = '';
}
if (count($this->summary))
{
$customSummary = '';
$summaryDetails = $this->_getSummaries();
foreach ($summaryDetails as $sectionName => $columns)
{
$sectionName .= ' ';
$customSummary .= "
<table cellpadding='0px' cellspacing='0px'
class='reportTable' style='width:230px;'>
<tr class='reportRow'>
<td class='reportHeader'rowspan='" . count($columns) .
"' style='width:200px;'>
" . $sectionName . "
</td>
<td class='reportHeader' style='width:150px;'>
";
foreach ($columns as $formulas)
{
foreach ($formulas as $formula)
{
switch ($formula->formula)
{
case 'AVERAGE' :$value = $formula->result->average; break;
case 'COUNT' :$value = $formula->result->count; break;
case 'PERCENT' :$value = $formula->result->percent; break;
case 'SUM' :$value = $formula->result->sum; break;
default :$value = ' ' ; $format = '%s';
}
$value = sprintf($formula->format, $value);
$format = $formula->format;
if ($formula->literal)
{
$description = $formula->name . ' ';
$customSummary .= "
<table cellpadding='0px' cellspacing='0px'
class='reportTable' style='width:230px;'>
<tr class='reportRow'>
<td class='reportHeader' style='width:150px;'>
" . $description . "
</td>
<td class='reportCell' style='text-align:right;
width:75px;'>
" . $value . "
</td>
</tr>
</table>
";
} else {
$description = ereg_replace('^{([^}]*)}$', '\\1',
$formula->name);
$description = $this->columns[$description]->alias . ' ' .
$formula->formula . ' ';
$customSummary .= "
<table cellpadding='0px' cellspacing='0px'
class='reportTable' style='width:225px;'>
<tr class='reportRow'>
<td class='reportHeader' style='width:150px'>
" . $description . "
</td>
<td class='reportHeader'
style='text-align:right;width:75px;'>
" . $value . "
</td>
</tr>
<tr class='reportRow'>
<td class='reportHeader' colspan='2'>
<table cellpadding='0px' cellspacing='0px'
class='reportTable' style='width:225px;'>
";
foreach ($formula->subGroups as $description => $subGroup)
{
$description .= ' ';
switch ($formula->formula)
{
case 'AVERAGE' :$value = $subGroup->average; break;
case 'COUNT' :$value = $subGroup->count; break;
case 'PERCENT' :$value = $subGroup->percent; break;
case 'SUM' :$value = $subGroup->sum; break;
default :$value = ' ' ; $format = '%s';
}
$value = sprintf($formula->format, $value);
$customSummary .= "
<tr class='reportRow'>
<td class='reportCell'
style='text-align:left;width:150px;'>
" . $description . "
</td>
<td class='reportCell'
style='text-align:right;width:75px;'>
" . $value . "
</td>
</tr>
";
}
$customSummary .= "
</table>
</td>
</tr>
</table>
";
}
}
}
$customSummary .= "
</td>
</tr>
</table>
<br />
";
}
}
$groupCount = count($this->groupings);
if ($groupCount == 0)
{
$html .= "
<table cellpadding='0px' cellspacing='0px' class='reportTable'>
<tr class='reportRow'>
<td class='reportHeader' style='width:150px'>TOTAL</td>
<td class='reportCell' style='text-align:right;width:75px'>
<b>" . $this->recordCount . "</b>
</td>
</tr>
</table>
<table cellpadding='0px' cellspacing='0px' class='reportTable'>
<tr class='reportRow'>
";
foreach ($this->display as $column)
{
$html .= "
<td class='reportHeader' style='text-align:right;'>
" . $column->alias . "
</td>
";
}
$html .= "
</tr>
<tr class='reportRow'>
";
foreach ($this->records as $record => $columns)
{
foreach ($this->display as $column)
{
$html .= "
<td class='reportCell'>
" . $this->records[$record][$column->name] . "
</td>
";
}
$html .= "
</tr>
";
}
$html .= "
</tr>
</table>
<table cellpadding='0px' cellspacing='0px' class='reportTable'>
<tr class='reportRow'>
<td class='reportHeader' style='width:150px;'>TOTAL</td>
<td class='reportCell' style='text-align:right;width:75px;'>
<b>" . $this->recordCount . "</b>
</td>
</tr>
</table>
";
return $header .
$customSummary .
"<br class='pageBreak'/>" .
$html .
"<br class='pageBreak'/>" .
$customSummary;
}
foreach ($this->groupings as $branch)
{
$grandTotal = 0;
$summary .= "
<table cellpadding='0px' cellspacing='0px' class='reportTable'
style='width:320px;'>
<tr class='reportRow'>
<td class='reportHeader' rowspan='" . count($branch->subGroups) .
"' style='width:200px;'>
" . $this->columns[$branch->name]->alias . "
</td>
<td class='reportHeader' style='width:150px;'>
";
if (count($branch->subGroups) != 0)
{
unset($subTotals);
$subTotals = array();
foreach ($branch->subGroups as $nest)
{
$subTotals[$nest->value] += $nest->total;
$grandTotal += $nest->total;
}
ksort($subTotals);
reset($subTotals);
foreach ($subTotals as $nest => $total)
{
$summary .= "
<table cellpadding='0px' cellspacing='0px' class='reportTable'
style='width:225px;'>
<tr class='reportRow'>
<td class='reportHeader' style='width:150px;'>
" . $nest . "
</td>
<td class='reportCell' style='text-align:right;width:75px;'>
" . $total . "
</td>
</tr>
</table>
";
}
$summary .= "
";
}
$summary .= "
<table cellpadding='0px' cellspacing='0px' class='reportTable'
style='width:225px;'>
<tr class='reportRow'>
<td class='reportHeader'
style='text-align:right;width:150px;'>TOTAL</td>
<td class='reportCell' style='text-align:right;width:75px;'>
<b>" . $grandTotal . "</b>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br/>
";
}
return $header .
$summary .
$customSummary .
$this->_getHTML($this->tree) .
$summary .
$customSummary;
}
function toXML()
{
$xml = "<?xml version='1.0' standalone='yes'?>\r\n";
$xml .= "<RECORDS>\r\n";
foreach ($this->records as $record => $columns)
{
$xml .= " <RECORD>\r\n";
foreach ($this->display as $column)
{
$columnName = $column->name;
$value = htmlspecialchars($columns[$columnName]);
$xml .= " <$columnName>$value</$columnName>\r\n";
}
$xml .= " </RECORD>\r\n";
}
$xml .= "</RECORDS>\r\n";
return $xml;
}
}
?>
Navigation:
[Reply to this message]
|