Source of: Report.php
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: *
// +----------------------------------------------------------------------+
// | PHP version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Sebastiao Rocha A Neto <rocha@i-node.com.br> |
// +----------------------------------------------------------------------+
//
// $Id: Report.php,v 1.18 2004/01/12 13:35:39 rocha Exp $
/**
* PHP Report:
*
* Generates a html report page from a result set
* array. That usually came from a sql query
* and isnt well formatted for display. This class
* 'prettyfy' the result using a template class, either
* IT,ITX or PHPLIB template
*
* Ex.:
*
* Inicial result set:
* ----------------------------------------------
* title subtitle value1 value2 value2
* ----------------------------------------------
* titulo1 subtitulo1 valor1 valor2 valor3
* titulo1 subtitulo1 valor1 valor2 valor3
* titulo1 subtitulo1 total1 total2 total3
* titulo1 subtitulo2 valor1 valor2 valor3
* titulo1 subtitulo2 valor1 valor2 valor3
* titulo1 subtitulo2 total1 total2 total3
* titulo2 subtitulo1 valor1 valor2 valor3
* titulo2 subtitulo1 valor1 valor2 valor3
* titulo2 subtitulo1 total1 total2 total3
* titulo2 subtitulo2 valor1 valor2 valor3
* titulo2 subtitulo2 total1 total2 total3
*
*
* Report output
* ============================================
* titulo1
* ---------------------------------------------
* subtitulo1
* ----------------------------
* valor1 valor2 valor3
* valor1 valor2 valor3
* subtitulo2
* ----------------------------
* valor1 valor2 valor3
* valor1 valor2 valor3
* ============================================
* titulo2
* ---------------------------------------------
* subtitulo1
* ----------------------------
* valor1 valor2 valor3
* valor1 valor2 valor3
* subtitulo2
* ----------------------------
* valor1 valor2 valor3
* valor1 valor2 valor3
* ----------------------------------------------
*
* The format is done on the template file like:
*
* <!-- BEGIN title -->
* {title}
* ---------------------------------------------
* <!-- BEGIN subtitle -->
* {subtitle}
* ----------------------------
* <!-- BEGIN values -->
* {value1} {value2} {value3}
* <!-- END values -->
* <!-- BEGIN totals -->
* {total1} {total2} {total3}
* <!-- END totals -->
*
* <!-- END subtitle -->
* ----------------------------------------------
* <!-- END title -->
*
**/
require_once("Report_template.php");
//require_once("Report_IT.php");
class Report extends ReportTemplate {
/**
* Array with columns names used for parse values '0' as null
* @access private
* @var array
**/
var $_nullforzero = array();
/**
* Raw result array
* @access private
* @var array
**/
var $_resultset = array();
/**
* Array with columns names used for (sub)titles
* @access private
* @var array
**/
var $_title = array();
/**
* Number of subtitle levels
*
* @access private
* @var integer
**/
var $_lastlevel = -1;
/**
* New array with the new rewritten array
*
* @access private
* @var array
**/
var $_result = array();
/**
* Boolean showtotals, if true the last line of
* block values is total, and have a template block
* apart to be parsed.
*
* @access private
* @var boolean
**/
var $_showtotals = false;
/**
*
* @access private
* @var string
**/
var $_blockvaluename = 'values';
/**
* @access private
* @var string
**/
var $_blocktotalname = 'totals';
/**
* Thousand separator (pt_BR stile)
*
* @access private
* @var string
**/
var $_thousand_sep = ',';
/**
* Decimal point (pt_BR style)
*
* @access private
* @var string
**/
var $_dec_point = '.';
/**
* Currency symbol (Brazilian real)
*
* @access private
* @var string
**/
var $_cur_symbol = 'R$';
/**
* HTML style to show negative values
*
* @access private
* @var string
**/
var $_negativestyle = '<font color="#FF0000">(%s)</font>';
/**
* Variable type for parsing befor show.
* Types: numeric, money, date
*
* @access private
* @var array
**/
var $_variabletype = array();
/**
* Number of decimals
*
* @access private
* @var integer
**/
var $_decimals = 2;
/**
*
* @access private
* @var array
**/
var $_totals = array();
/**
* Date regex, use to extract fields from database columns
* @access private
* @var string
**/
var $_dateregex = "([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})";
/**
*
* @access private
* @var string
**/
var $_datetimeregex = "([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})\s+([^\s]+)";
/**
* Use european style for days (DD/MM/YYYY) or (MM/DD/YYY)?
* @access public
* @var string
**/
var $europeanstyle = true;
/**
* Report::Report()
*
* Constructor
* @access protected
* @param $result
**/
function Report(&$resultset, $dir, $file)
{
$this->setResultSet($resultset);
$this->debug = false;
$this->_file = $file;
$this->_dir = $dir;
$this->setup();
}
/**
* Report::setTitle()
*
* Template independent function.
* Set the name of columns to use as title/subtitles. $level tells the
* position the title in the hierachie. Accepts an array or a pair (title, level)
*
* @param $title
* @param unknown $level
* @return void
**/
function setTitle($title, $level = null)
{
if ( isset($level)) {
$this->_title[$level] = $title;
$this->_lastlevel = $level;
} else {
if ( is_array($title)) {
foreach ($title as $level => $name) {
$this->_title[$level] = $name;
$this->_lastlevel = $level;
}
} else {
/**
* Raise error
**/
return new PEAR_Error("Unable to set title, unknown args.", -1);
}
}
}
/**
* Report::rewriteArray()
*
* Template independent function.
* Remove one column from the array and returns a new array
*
* Needs a array:
* title value1 value2
* ------------------------
* array ( '1' => array(titulo1, valor1, valor2),
* '2' => array(titulo1, valor1, valor2),
* '3' => array(titulo1, valor1, valor2)
* )
*
* Returns
* array (
* 'titulo1' => array( '1' => array( valor1, valor2),
* '2' => array( valor1, valor2),
* '3' => array( valor1, valor2)
* )
* )
* @param $title
* @param $oldarray
* @return
**/
function &rewriteArray($colname, &$oldarray)
{
$part = array();
foreach ($oldarray as $idx => $list) {
$name = $list[$colname];
if ( isset($count[$name])) {
$count[$name]++;
} else {
$count[$name] = 0;
}
unset($list[$colname]);
$part[$name][$count[$name]] = $list;
}
// print_r($part);
return $part;
}
/**
* Report::rewriteResultSet()
*
* Template independent function.
* Recursive function to write the final array as
* $result[$title][$subtitle]...[] = array ( value1 => 'valor1', ...etc);
*
* @param string $list
* @return mixed array with parcial result written.
**/
function &rewriteResultSet($list = "")
{
static $level = 0;
$title = $this->_title[$level];
if (!$level ) {
if (!$list) {
$list =& $this->getResult(); // (i) => array()
}
$list =& $this->rewriteArray($title, $list); // (name)(i) => array()
$level++;
foreach ($list as $titlevalue => $newlist) {
$reslist[$titlevalue] = $this->rewriteResultSet(&$newlist);
}
$level--; // back one level
return $reslist;
} elseif ($level <= $this->_lastlevel) {
$list =& $this->rewriteArray($title, $list);
$level++;
foreach ($list as $titlevalue => $newlist) {
$reslist[$titlevalue] = $this->rewriteResultSet(&$newlist);
}
$level--; // back one level
return $reslist;
} else {
return $list;
}
}
/**
* Report::makeReport()
*
* Recursive function to create the report
* from the rewritten array
*
* @param string $list
* @return
**/
function makeReport($list = "")
{
static $showlevel = 0;
if (!$list && isset($this->_title[$showlevel]) ) {
$list = $this->rewriteResultSet();
} elseif(!$list) {
$list = $this->getResult(); // (i) => array()
}
if (!$showlevel && isset($this->_title[$showlevel])) {
$titlename = $this->_title[$showlevel];
$showlevel++;
foreach($list as $title => $newlist) {
$this->_titlevalues[$titlename]=$title;
$this->makeReport($newlist);
$this->blockParser($titlename, $title);
$this->cleanBlock($this->_title[$showlevel]); // Only used in phplib template.inc
}
// Finishing the recursion, show the gran total if we were asked to.
if($this->_blockgrantotalname) {
$this->parseFinal($this->_grantotals, $this->_blockgrantotalname);
}
$showlevel--;
} elseif (isset($this->_lastlevel) && ($showlevel <= $this->_lastlevel)) {
$titlename = $this->_title[$showlevel];
$showlevel++;
foreach($list as $title => $newlist) {
$this->_titlevalues[$titlename]=$title;
$this->makeReport($newlist);
$this->blockParser($titlename, $title);
$this->cleanBlock($this->_title[$showlevel]); // Only used in phplib template.inc
}
$showlevel--;
} else {
/**
* End of line, parse the values
* Set variables values
**/
$this->parseVariables(&$list);
}
}
/**
*
*/
function setGranTotalBlock($val)
{
$this->_blockgrantotalname = $val;
}
/**
* @access public
* @return array
**/
function setNullForZero($zeroValue)
{
if (is_array($zeroValue)) {
foreach($zeroValue as $zero) {
$this->_nullforzero[$zero] = true;
}
} elseif (is_string($zeroValue)) {
$this->_nullforzero[$zeroValue] = true;
}
}
/**
* Get the current result array
*
* @access public
* @return void
**/
function & getResult()
{
if (!$this->_result) {
return $this->_resultset;
} else {
return $this->_result;
}
}
/**
* @access public
* @return array
**/
function setResult($newValue)
{
$this->_result = $newValue;
}
/**
* Get the raw resultset array
*
* @access public
* @return array
**/
function getResultSet()
{
return $this->_resultset;
}
/**
* Set the raw result set array
* @access public
* @return array
**/
function setResultSet($newValue)
{
/**
* Since we can have result columns coming
* from evaluation of expressions, if they exists we insert then
* in the resultset. The value here doesnt matter yet.
**/
$temp = $newValue;
if( is_array($this->_expression) ) {
foreach($this->_expression as $name => $value ){
//echo "Set result: $name = $value <br>";
foreach($temp as $i => $dummy ) {
$newValue[$i][$name] = '';
}
}
}
$this->_resultset =& $newValue;
}
/**
* Get the number of subtitles
* @access public
* @return integer
**/
function getLastLevel()
{
return $this->_lastlevel;
}
/**
* Set the number of subtitles
* @access public
* @return void
**/
function setLastLevel($newValue)
{
$this->_lastlevel = $newValue;
}
/**
* @access public
* @return boolean
**/
function getShowTotals()
{
return $this->_showtotals;
}
/**
* @access public
* @return void
**/
function setShowTotals($newValue)
{
$this->_showtotals = $newValue;
}
/**
*
* @access public
* @return string
**/
function getBlockValueName(){
return $this->_blockvaluename;
}
/**
*
* @access public
* @return void
**/
function setBlockValueName($newValue){
$this->_blockvaluename = $newValue;
}
/**
*
* @access public
* @return string
**/
function getBlockTotalName(){
return $this->_blocktotalname;
}
/**
*
* @access public
* @return void
**/
function setBlockTotalName($newValue){
$this->_blocktotalname = $newValue;
}
/**
* Report::setVar()
*
* Wrapper for setVariable's IT method.
* It does some formatting before set parse template
* variables. Also accumlate totals if that was set.
*
* @param $variable
* @param string $value
* @return
**/
function setVar($variable, $value="")
{
if (is_array($variable)) {
$this->_currentlist = $variable;
foreach ($variable as $name => $value) {
/**
* See if we are collecting totals
*
**/
if( $this->_totalizing ){
/**
* See if we have a expression to eval.
*/
if( $this->_expression[$name] ) {
$value = $this->evaluateExpression($name);
}
if( $this->_functions[$name] ) {
$value = $this->evaluateFunction($name, $value);
}
/**
* See if we have to do some accounting.
*/
if( $this->doTotals[$name] ) {
$this->_totals[$name] += $value;
$this->_grantotals[$name] += $value;
}
}
/**
* Parse the value.
*/
$newvalue = $this->parseValue($name, $value);
$this->replaceVar($name, $newvalue);
}
} else {
/**
* See if we have to do some accounting.
*/
if( $this->doTotals[$variable] ) {
$this->_totals[$variable] += $value;
}
/**
* See if we have to do some accounting.
*/
if( $this->_functions[$variable] ) {
$value = $this->evaluateFunction($variable, $value);
}
/**
* See if we have a expression to eval.
*/
if( $this->_expression[$variable] ) {
$value = $this->evaluateExpression($variable);
}
/**
* Parse the value.
*/
$newvalue = $this->parseValue($variable, $value);
$this->replaceVar($variable, $newvalue);
}
}
/**
*
* @access public
* @return string
**/
function getTotals(){
return $this->_totals;
}
/**
*
* @access public
* @return array
**/
function setTotals($newValue)
{
if(isset($newValue)) {
$this->_showtotals = $newValue;
}
$this->doTotals = $newValue;
}
/**
* Report::evaluateFunction()
*
* @param $name
* @return
**/
function evaluateFunction($name, $value)
{
$function = $this->getFunction($name);
$val = $function($value);
return $val;
}
/**
* Report::getFunction()
*
* @param $name
* @return
**/
function getFunction($name)
{
return $this->_functions[$name];
}
/**
* Report::setFunctions()
*
* @param $name
* @return
**/
function setFunctions($f)
{
$this->_functions = $f;
}
/**
* Report::evaluateExpression()
*
* @param $name
* @return
**/
function evaluateExpression($name)
{
$expression = $this->getExpression($name);
foreach ($this->_currentlist as $var => $value) {
if (!isset($value)) {
$value = "0";
}
$expression = str_replace("{".$var."}", $value, $expression);
}
// Some var can be at the title array, we dont want do miss them.
if ($this->_titlevalues) {
reset($this->_titlevalues);
while (list($var, $value) = each($this->_titlevalues)) {
$expression = str_replace("{".$var."}", $value, $expression);
}
reset($this->_titlevalues);
}
eval("\$expression = $expression;");
// Since we added the new column for the expression without a value now we load it.
$this->_currentlist[$name] = $expression;
return $expression;
}
/**
* Report::getExpression()
*
* @param $name
* @return
**/
function getExpression($name)
{
return $this->_expression[$name];
}
/**
* Report::setExpression()
*
* @param $name
* @param $expression
* @return
**/
function setExpression($name, $expression, $type="numeric")
{
$this->_expression[$name] = $expression;
$this->_variabletype[$name] = $type;
// Add a new 'virtual' column to the list
foreach($this->_resultset as $i => $nada) {
$this->_resultset[$i][$name] = '';
}
}
/**
* Report::parseValue()
*
* @param $variable
* @param $value
* @return
**/
function parseValue($variable, $value)
{
$type = $this->getVariableType($variable);
switch ($type) {
case "date":
$regex = $this->getDateRegex();
if (eregi($regex, $value, $regs)) {
if($this->europeanstyle) {
$newvalue = sprintf("%s/%s/%s",$regs[3],$regs[2],$regs[1]);
} else {
$newvalue = sprintf("%s/%s/%s",$regs[2],$regs[3],$regs[1]);
}
} else {
$newvalue = $value;
}
break;
case "datetime":
$regex = $this->_datetimeregex;
if (eregi($regex, $value, $regs)) {
$newvalue = sprintf("%s/%s/%s %s",$regs[3],$regs[2],$regs[1], $regs[4]);
} else {
$newvalue = $value;
}
break;
case "money":
$thousand = $this->getThousandSeparator();
$decimals = 2;
$decpoint = $this->getDecimalPoint();
if ($this->_negativestyle && $value < 0) {
$value = -$value;
$value = number_format($value, $decimals, $thousand, $decpoint);
$value = $this->getNegativeStyle($value);
$value = $this->getCurrencySymbol() . " " . $value;
} else {
$value = number_format($value, $decimals, $thousand, $decpoint);
$value = $this->getCurrencySymbol() . " " . $value;
}
$newvalue = $value;
break;
case "select":
$combo = $this->combos[$variable];
$i=0;
while ($combo[$i]) {
if (trim($combo[$i]["value"]) == trim($value)) {
if (ereg( "^\s*$", $value)) {
$newvalue = "";
} else {
$newvalue = $combo[$i]["label"];
}
}
$i++;
}
break;
case "numeric":
$thousand = $this->getThousandSeparator();
$decimals = $this->getDecimals();
$decpoint = $this->getDecimalPoint();
if ($this->_negativestyle && $value < 0) {
$value = -$value;
$value = number_format($value, $decimals, $thousand, $decpoint);
$value = $this->getNegativeStyle($value);
} else {
$value = number_format($value, $decimals, $thousand, $decpoint);
}
$newvalue = $value;
break;
case "percent":
if ($this->_nullforzero[$variable] && !$value) {
$newvalue = "";
}
$thousand = $this->getThousandSeparator();
$decimals = $this->getDecimals();
$decpoint = $this->getDecimalPoint();
if ($this->_negativestyle && $value < 0) {
$value = -$value;
$value = number_format($value, $decimals, $thousand, $decpoint) . "%";
$value = $this->getNegativeStyle($value);
} else {
$value = number_format($value, $decimals, $thousand, $decpoint) . "%";
}
$newvalue = $value;
default:
$newvalue = $value;
} // switch
return $this->ifForm($variable, $newvalue);
}
/**
* Se o campo pertence a um form rederiza o tag com o valor
* já formatado.
*/
function ifForm($var, $val)
{
if( $this->formfield[$var] ) {
$this->form->elements[$this->_namespace.$var]['ob']->value = $GLOBALS[$this->_namespace.$var];
return $this->form->ge($this->_namespace.$var, $val);
}
return $val;
}
/**
*
* @access public
* @return string
**/
function getDateRegex(){
return $this->_dateregex;
}
/**
*
* @access public
* @return void
**/
function setDateRegex($newValue){
$this->_dateregex = $newValue;
}
/**
*
* @access public
* @return integer
**/
function getDecimals(){
return $this->_decimals;
}
/**
*
* @access public
* @return void
**/
function setDecimals($newValue){
$this->_decimals = $newValue;
}
/**
*
* @access public
* @return string
**/
function getVariableType($name){
return $this->_variabletype[$name];
}
/**
*
* @access public
* @return array
**/
function setVariableType($newValue){
$this->_variabletype = $newValue;
}
/**
*
* @access public
* @return string
**/
function getNegativeStyle($value){
$string = $this->_negativestyle;
$string = sprintf($string, $value);
return $string;
}
/**
*
* @access public
* @return void
**/
function setNegativeStyle($newValue){
$this->_negativestyle = $newValue;
}
/**
*
* @access public
* @return string
**/
function getCurrencySymbol(){
return $this->_cur_symbol;
}
/**
*
* @access public
* @return void
**/
function setCurrencySymbol($newValue){
$this->_cur_symbol = $newValue;
}
/**
*
* @access public
* @return string
**/
function getThousandSeparator(){
return $this->_thousand_sep;
}
/**
*
* @access public
* @return void
**/
function setThousandSeparator($newValue){
$this->_thousand_sep = $newValue;
}
/**
*
* @access public
* @return string
**/
function getDecimalPoint(){
return $this->_dec_point;
}
/**
*
* @access public
* @return void
**/
function setDecimalPoint($newValue){
$this->_dec_point = $newValue;
}
}
?>
Processed: 2010/Sep/08 11:56:27