1060 lines
31 KiB
PHP
1060 lines
31 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* AgileBill - Open Billing Software
|
||
|
*
|
||
|
* This body of work is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the Open AgileBill License
|
||
|
* License as published at http://www.agileco.com/agilebill/license1-4.txt
|
||
|
*
|
||
|
* For questions, help, comments, discussion, etc., please join the
|
||
|
* Agileco community forums at http://forum.agileco.com/
|
||
|
*
|
||
|
* @link http://www.agileco.com/
|
||
|
* @copyright 2004-2008 Agileco, LLC.
|
||
|
* @license http://www.agileco.com/agilebill/license1-4.txt
|
||
|
* @author Tony Landis <tony@agileco.com> and Thralling Penguin, LLC <http://www.thrallingpenguin.com>
|
||
|
* @package AgileBill
|
||
|
* @version 1.4.93
|
||
|
*/
|
||
|
|
||
|
class LevelGraph extends Level_Base {
|
||
|
|
||
|
var $lev_setting;
|
||
|
var $lev_items;
|
||
|
var $SQL_filtered;
|
||
|
var $group_level;
|
||
|
var $grouping_criteria;
|
||
|
var $formatter;
|
||
|
var $graph;
|
||
|
var $plotarea;
|
||
|
var $dataset;
|
||
|
var $canvas;
|
||
|
|
||
|
function LevelGraph (
|
||
|
$title = '',
|
||
|
$width=800,
|
||
|
$height=300,
|
||
|
$type='bar',
|
||
|
$direction = 'vertical',
|
||
|
$x_angle = 90)
|
||
|
{
|
||
|
if(!strlen($direction)) $direction = 'vertical';
|
||
|
|
||
|
$this->lev_setting = array(
|
||
|
"title" => $title,
|
||
|
"width" => $width,
|
||
|
"height" => $height,
|
||
|
"y_label_angle" => 0,
|
||
|
"x_label_angle" => intval($x_angle),
|
||
|
"type" => $type,
|
||
|
"direction" => $direction,
|
||
|
"SQL_criteria" => ''
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function addDataset ($SQL_select, $SQL_criteria='', $SQL_order='')
|
||
|
{
|
||
|
$this->dataset[] = array(
|
||
|
"SQL_select" => $SQL_select,
|
||
|
"SQL_criteria" => $SQL_criteria,
|
||
|
"SQL_order" => $SQL_order
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function display ($grouping_criteria = Null, $grouping_aggregate = Null, &$formatter)
|
||
|
{
|
||
|
$this->formatter =& $formatter;
|
||
|
$this->formatter->setLevel($this);
|
||
|
$this->grouping_criteria = $grouping_criteria;
|
||
|
$this->grouping_aggregate = $grouping_aggregate;
|
||
|
|
||
|
$this->group_level = false;
|
||
|
if (count($this->lev_items) > 0) {
|
||
|
$this->group_level = true;
|
||
|
}
|
||
|
|
||
|
set_include_path(get_include_path().PATH_SEPARATOR.PATH_INCLUDES."pear");
|
||
|
include_once 'Image/Graph.php';
|
||
|
include_once 'Image/Canvas.php';
|
||
|
|
||
|
$this->canvas =& Image_Canvas::factory('png', array(
|
||
|
'width' => $this->lev_setting["width"],
|
||
|
'height' => $this->lev_setting["height"],
|
||
|
'antialias' => 'native'
|
||
|
));
|
||
|
|
||
|
$this->graph =& Image_Graph::factory('graph', $this->canvas);
|
||
|
$this->plotarea =& $this->graph->addNew('plotarea',array(
|
||
|
'Image_Graph_Axis_Category', 'Image_Graph_Axis', $this->lev_setting['direction']
|
||
|
));
|
||
|
|
||
|
$this->plotarea->setFillColor('black@0.1');
|
||
|
#$this->plotarea->showShadow();
|
||
|
|
||
|
$AxisX =& $this->plotarea->getAxis(IMAGE_GRAPH_AXIS_X);
|
||
|
$AxisY =& $this->plotarea->getAxis(IMAGE_GRAPH_AXIS_Y);
|
||
|
|
||
|
$AxisX->setFontAngle($this->lev_setting["x_label_angle"]);
|
||
|
$AxisY->setFontAngle($this->lev_setting["y_label_angle"]);
|
||
|
|
||
|
foreach($this->dataset as $dset) {
|
||
|
$SQL_criteria = '';
|
||
|
if ($dset['SQL_criteria'] != '') {
|
||
|
$SQL_criteria = $this->addToFilter($SQL_criteria,
|
||
|
$dset['SQL_criteria']);
|
||
|
}
|
||
|
#echo "C1: ".$SQL_criteria."<BR>";
|
||
|
if ($this->lev_setting['SQL_criteria'] != '') {
|
||
|
$SQL_criteria = $this->addToFilter($SQL_criteria,
|
||
|
$this->lev_setting['SQL_criteria']);
|
||
|
}
|
||
|
#echo "C2: ".$SQL_criteria."<BR>";
|
||
|
if (count($this->grouping_criteria) > 0) {
|
||
|
foreach ($this->grouping_criteria as $key => $value) {
|
||
|
$SQL_criteria = $this->addToFilter($SQL_criteria,
|
||
|
"$key = $value",
|
||
|
$this->grouping_aggregate[$key]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
#echo "C3: ".$SQL_criteria."<BR>";
|
||
|
$this->SQL_filtered = $this->shuffleSQL($dset["SQL_select"].$SQL_criteria." ".$dset["SQL_order"]);
|
||
|
if(defined('REPORT_DEBUG'))
|
||
|
echo "<br>The SQL_filtered is: " . $this->SQL_filtered . "<br>";
|
||
|
$db =& DB();
|
||
|
$result = $db->Execute($this->SQL_filtered);
|
||
|
if(!$result) {
|
||
|
echo "SQL: ".$this->SQL_filtered."<br>".$db->ErrorMsg();
|
||
|
exit;
|
||
|
}
|
||
|
$num_rows = $result->RecordCount();
|
||
|
|
||
|
if ($num_rows == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$Dataset =& Image_Graph::factory('dataset');
|
||
|
while(!$result->EOF) {
|
||
|
$Dataset->addPoint($result->fields[0],$result->fields[1]);
|
||
|
$result->MoveNext();
|
||
|
}
|
||
|
$Plot =& $this->plotarea->addNew($this->lev_setting["type"], &$Dataset);
|
||
|
}
|
||
|
|
||
|
$file = tempnam($this->formatter->output_path."/", "s");
|
||
|
@unlink($file);
|
||
|
$file .= ".png";
|
||
|
$this->graph->done(
|
||
|
array('filename' => $file)
|
||
|
);
|
||
|
|
||
|
# add to output
|
||
|
$this->formatter->insertImage(
|
||
|
$file,
|
||
|
$this->lev_setting["width"],
|
||
|
$this->lev_setting["height"]
|
||
|
);
|
||
|
|
||
|
#intersperse and whatnot
|
||
|
if ($this->group_level === true) {
|
||
|
$this->formatter->endTable();
|
||
|
}
|
||
|
if ($this->group_level === true) {
|
||
|
$this->intersperse($this->grouping_criteria,$this->grouping_aggregate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Level extends Level_Base {
|
||
|
|
||
|
var $lev_setting;
|
||
|
var $lev_fields;
|
||
|
var $lev_items;
|
||
|
var $indent_html;
|
||
|
var $SQL_filtered;
|
||
|
var $group_level;
|
||
|
var $grouping_criteria;
|
||
|
var $has_title;
|
||
|
var $formatter;
|
||
|
var $add_headers = 0;
|
||
|
var $class;
|
||
|
|
||
|
function Level ($title='',
|
||
|
$SQL_select='', $SQL_criteria='', $SQL_order='',
|
||
|
$title_table_class='title', $title_class='', $indent=0,
|
||
|
$lev_field_width = '',
|
||
|
$lev_field_class = 'row', $lev_label_class = '', $lev_table_class = 'level',
|
||
|
$lev_tot_class = 'rc-lev-tot1', $lev_colspan_label_class = 'rc-lev-colspan-label1')
|
||
|
{
|
||
|
|
||
|
if($lev_field_class == 'row') {
|
||
|
$lev_field_class = new ReportStyle;
|
||
|
$lev_field_class->backgroundColor(230,230,230);
|
||
|
}
|
||
|
if($lev_label_class == '') {
|
||
|
$lev_label_class = new ReportStyle;
|
||
|
$lev_label_class->bold();
|
||
|
$lev_label_class->fontFamily('arial');
|
||
|
$lev_label_class->is_heading = true;
|
||
|
}
|
||
|
|
||
|
$this->lev_setting = array(
|
||
|
"title" => $title,
|
||
|
"SQL_select" => $SQL_select,
|
||
|
"SQL_criteria" => $SQL_criteria,
|
||
|
"SQL_order" => $SQL_order,
|
||
|
"title_class_html" => $title_class,
|
||
|
"title_table_class_html" => $title_table_class,
|
||
|
"indent" => $indent,
|
||
|
"lev_field_width" => $lev_field_width,
|
||
|
"lev_field_class" => $lev_field_class,
|
||
|
"lev_label_class" => $lev_label_class,
|
||
|
"lev_table_class_html" => $lev_table_class,
|
||
|
"lev_tot_class" => $lev_tot_class,
|
||
|
"lev_colspan_label_class" => $lev_colspan_label_class,
|
||
|
"class" => ''
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function setTitle($t)
|
||
|
{
|
||
|
$this->lev_setting["title"] = $t;
|
||
|
}
|
||
|
|
||
|
function setSql($s)
|
||
|
{
|
||
|
$this->lev_setting["SQL_select"] = $s;
|
||
|
}
|
||
|
|
||
|
function setCriteria($c)
|
||
|
{
|
||
|
$this->lev_setting["SQL_criteria"] = $c;
|
||
|
}
|
||
|
|
||
|
function setOrderby($o)
|
||
|
{
|
||
|
$this->lev_setting["SQL_order"] = $o;
|
||
|
}
|
||
|
|
||
|
function setIndent($i)
|
||
|
{
|
||
|
$this->lev_setting["indent"] = $i;
|
||
|
return $i;
|
||
|
}
|
||
|
|
||
|
function setClass($c)
|
||
|
{
|
||
|
$this->lev_setting["class"] = $c;
|
||
|
}
|
||
|
|
||
|
function addField ($label, $name, $isAggregate = false, $width = '', $format = '',
|
||
|
$group_children_by = false, $visible = true, $hide_dups = false,
|
||
|
$class = '', $lev_class_also = false, $label_class = '', $lev_label_class_also = false,
|
||
|
$condition = '', $cond_class = '',
|
||
|
$SQL_select = '', $SQL_criteria = '',
|
||
|
$colspan = 0, $colspan_label = '', $colspan_label_class = '', $lev_colspan_class_also = false,
|
||
|
$has_tot = false, $tot_label = '', $tot_format = '', $tot_class = '', $lev_tot_class_also = false,
|
||
|
$link = '')
|
||
|
{
|
||
|
//NB every field added MUST be in the source SQL
|
||
|
//if a grouping variable, then set group_children_by to True
|
||
|
//if a field is an aggregate, then it must be True. This causes it's usage to be in HAVING clause, instead of WHERE
|
||
|
|
||
|
if ($link != "") {
|
||
|
$is_link = True;
|
||
|
$link_text_start = $link["link_text_start"];
|
||
|
$link_text_end = $link["link_text_end"];
|
||
|
$link_title_start = $link["link_title_start"];
|
||
|
$link_title_end = $link["link_title_end"];
|
||
|
$link_href_start = $link["link_href_start"];
|
||
|
$link_href_end = $link["link_href_end"];
|
||
|
} else {
|
||
|
$is_link = False;
|
||
|
$link_text_start = "";
|
||
|
$link_text_end = "";
|
||
|
$link_title_start = "";
|
||
|
$link_title_end = "";
|
||
|
$link_href_start = "";
|
||
|
$link_href_end = "";
|
||
|
}
|
||
|
|
||
|
if($tot_class == '') {
|
||
|
$tot_class = new ReportStyle;
|
||
|
$tot_class->backgroundColor(200,200,200);
|
||
|
}
|
||
|
$this->lev_fields[$name] = array("field_label"=>$label,
|
||
|
"field_name"=>$name,
|
||
|
"field_aggregate"=>$isAggregate,
|
||
|
"colspan"=>$colspan,
|
||
|
"colspan_label"=>$colspan_label,
|
||
|
"colspan_label_class"=>$colspan_label_class,
|
||
|
"lev_colspan_class_also"=>$lev_colspan_class_also,
|
||
|
"field_SQL_select"=>$SQL_select,
|
||
|
"field_SQL_criteria"=>$SQL_criteria,
|
||
|
"group_children_by"=>$group_children_by,
|
||
|
"visible"=>$visible,
|
||
|
"hide_duplicates"=>$hide_dups,
|
||
|
"field_width"=>$width,
|
||
|
"field_format"=>$format,
|
||
|
"field_class"=>$class,
|
||
|
"lev_class_also" =>$lev_class_also,
|
||
|
"field_label_class"=>$label_class,
|
||
|
"lev_label_class_also"=>$lev_label_class_also,
|
||
|
"field_condition"=>$condition,
|
||
|
"field_cond_class"=>$cond_class,
|
||
|
"has_tot"=>$has_tot,
|
||
|
"tot_label"=>$tot_label,
|
||
|
"field_tot_format"=>$tot_format,
|
||
|
"field_tot_class"=>$tot_class,
|
||
|
"lev_tot_class_also"=>$lev_tot_class_also,
|
||
|
"is_link"=>$is_link,
|
||
|
"link_text_start"=>$link_text_start,
|
||
|
"link_text_end"=>$link_text_end,
|
||
|
"link_title_start"=>$link_title_start,
|
||
|
"link_title_end"=>$link_title_end,
|
||
|
"link_href_start"=>$link_href_start,
|
||
|
"link_href_end"=>$link_href_end
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function display ($grouping_criteria = Null, $grouping_aggregate = Null, &$formatter)
|
||
|
{
|
||
|
$this->formatter =& $formatter;
|
||
|
$this->formatter->setLevel($this);
|
||
|
$this->grouping_criteria = $grouping_criteria;
|
||
|
$this->grouping_aggregate = $grouping_aggregate;
|
||
|
|
||
|
#echo "Freshly received grouping criteria: " . print_r($this->grouping_criteria); //check
|
||
|
|
||
|
$this->group_level = false;
|
||
|
if (count($this->lev_items) > 0) {
|
||
|
$this->group_level = true;
|
||
|
}
|
||
|
|
||
|
$SQL_criteria = '';
|
||
|
if ($this->lev_setting['SQL_criteria'] != '') {
|
||
|
$SQL_criteria = $this->addToFilter($SQL_criteria,
|
||
|
$this->lev_setting['SQL_criteria']);
|
||
|
}
|
||
|
|
||
|
if (count($this->grouping_criteria) > 0) {
|
||
|
foreach ($this->grouping_criteria as $key => $value) {
|
||
|
$SQL_criteria = $this->addToFilter($SQL_criteria,
|
||
|
"$key = $value",
|
||
|
$this->grouping_aggregate[$key]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//echo "<br>The row filter clause is: " . $SQL_criteria , "<br>"; //check
|
||
|
// 2-2) put select, where, and order clauses together
|
||
|
$this->SQL_filtered = $this->shuffleSQL($this->lev_setting["SQL_select"].$SQL_criteria." ".$this->lev_setting["SQL_order"]);
|
||
|
|
||
|
if(defined('REPORT_DEBUG'))
|
||
|
echo "<br>The SQL_filtered is: " . $this->SQL_filtered . "<br>"; //check
|
||
|
|
||
|
|
||
|
$db =& DB();
|
||
|
$result = $db->Execute($this->SQL_filtered);
|
||
|
if(!$result) {
|
||
|
echo "SQL: {$this->SQL_filtered}<br>".$db->ErrorMsg();
|
||
|
exit;
|
||
|
}
|
||
|
$num_rows = $result->RecordCount();
|
||
|
if ($num_rows == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$this->indent_html = $this->setIndent($this->lev_setting['indent']);
|
||
|
|
||
|
// 3-3) insert level title if needed
|
||
|
$this->has_title = False;
|
||
|
if ($this->lev_setting["title"] != '') {
|
||
|
$this->has_title = true;
|
||
|
}
|
||
|
|
||
|
$heading = '';
|
||
|
if ($this->has_title === true) {
|
||
|
if(is_a($this->formatter,'HTML_ReportFormatter')) {
|
||
|
$this->formatter->setIndent($this->indent_html);
|
||
|
$heading = '<div id="title">'.$this->lev_setting["title"].'</div>';
|
||
|
|
||
|
} else {
|
||
|
$this->formatter->setIndent($this->indent_html);
|
||
|
$this->formatter->addTable($this->lev_setting["title_table_class_html"]);
|
||
|
$this->formatter->addRow();
|
||
|
$this->formatter->addColumn($this->lev_setting["title"],
|
||
|
$this->lev_setting["title_class_html"]
|
||
|
);
|
||
|
$this->formatter->endRow();
|
||
|
$this->formatter->endTable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//if a final row, use header-style labels
|
||
|
if ($this->group_level === false) {
|
||
|
|
||
|
$this->formatter->setIndent($this->indent_html);
|
||
|
$this->addHeaderLabels($heading);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*set these up once before rows begin (needed for hide_duplicates)*/
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
$content[$field['field_name']] = ''; //seed/reset
|
||
|
$last_content[$field['field_name']] = ''; //seed/reset
|
||
|
//each of these is an array with an item for each field value in the row
|
||
|
}
|
||
|
|
||
|
|
||
|
// 4) DISPLAY EACH ROW >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||
|
while (!$result->EOF) {
|
||
|
$row = $result->fields;
|
||
|
$result->MoveNext();
|
||
|
|
||
|
// 4-1) display each visible field (from supplied field argument) within row
|
||
|
|
||
|
//if level is group level (no header row) need to start table and body (one for each level)
|
||
|
|
||
|
if ($this->group_level === true) {
|
||
|
if(strlen($this->lev_setting['class']))
|
||
|
$this->formatter->write('<div id="'.$this->lev_setting["class"].'">');
|
||
|
$this->formatter->setIndent($this->indent_html);
|
||
|
$this->formatter->addTable($this->lev_setting["lev_table_class_html"],$heading);
|
||
|
}
|
||
|
|
||
|
$this->formatter->addRow();
|
||
|
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
|
||
|
// 4-1-0) only display field if visible
|
||
|
if ($field['visible'] === false) {
|
||
|
continue; //skip this field
|
||
|
}
|
||
|
|
||
|
// 4-1-1) set up class(es)
|
||
|
|
||
|
//only make label classes html if a group level
|
||
|
if ($this->group_level === true) {
|
||
|
/*must create class html here - it is a combination of level and
|
||
|
field class settings */
|
||
|
|
||
|
$field_label_class_html = $this->classHtml($field["field_label_class"],
|
||
|
$this->lev_setting["lev_label_class"],
|
||
|
$field["lev_class_also"]);
|
||
|
}
|
||
|
|
||
|
/*if a conditional class, see if condition met. If it is, use field_conditional class
|
||
|
instead of standard field class*/
|
||
|
|
||
|
$condition_met = false; //initialise
|
||
|
if ($field['field_condition'] != '') {
|
||
|
//get condition
|
||
|
$condition_met = $this->makeCondition($field['field_condition'],
|
||
|
$row, $this->lev_fields
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if ($condition_met === true) {
|
||
|
$field_class = $field['field_cond_class'];
|
||
|
} else {
|
||
|
$field_class =$field['field_class'];
|
||
|
}
|
||
|
|
||
|
$field_class_html = $this->classHtml($field_class,
|
||
|
$this->lev_setting['lev_field_class'],
|
||
|
$field['lev_class_also']);
|
||
|
|
||
|
$field_width_html = $this->setWidth ($field["field_width"], $this->lev_setting["lev_field_width"]);
|
||
|
|
||
|
if ($field["field_SQL_select"] != '') { //if this field has its own data source ...
|
||
|
|
||
|
/* 5-1-3-1) set up WHERE/HAVING clause using both parent-derived criteria
|
||
|
(if the level above is team='CommunityCare' then this record source needs to be filtered to
|
||
|
only include data for the CommunityCare team*/
|
||
|
|
||
|
$field_SQL_criteria = "";
|
||
|
|
||
|
if ($field["field_SQL_criteria"] != "") {
|
||
|
|
||
|
$field_SQL_criteria = $this->addToFilter($field_SQL_criteria,
|
||
|
$field["field_SQL_criteria"]);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if (count($this->grouping_criteria) > 0) {
|
||
|
|
||
|
foreach ($this->grouping_criteria as $key => $value) {
|
||
|
|
||
|
$field_SQL_criteria = $this->addToFilter($field_SQL_criteria, "$key = $value");
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
if($field["field_name"]!="") {
|
||
|
$dba = DB();
|
||
|
$field_SQL_criteria = $this->addToFilter($field_SQL_criteria, $field["field_name"]." = ".$dba->qstr($row[$field["field_name"]]));
|
||
|
}
|
||
|
|
||
|
|
||
|
//echo "<br>The field filter clause is: " . $field_SQL_criteria , "<br>"; //check
|
||
|
|
||
|
/* 4-1-3-2) put select, where (but not order - not applicable -
|
||
|
order derived from other fields) parts of SQL statement together*/
|
||
|
|
||
|
$field_SQL_filtered = $this->shuffleSQL($field["field_SQL_select"] . $field_SQL_criteria);
|
||
|
|
||
|
#echo "<br>The field_SQL_filtered is: " . $field_SQL_filtered . "<br>"; //check
|
||
|
|
||
|
// 4-1-3-3) get the content according to the SQL statement
|
||
|
|
||
|
$db = DB();
|
||
|
$rs = $db->Execute($field_SQL_filtered);
|
||
|
if($rs && $rs->RecordCount()) {
|
||
|
$content[$field["field_name"]] = $rs->fields[0];
|
||
|
}
|
||
|
|
||
|
} else { //take content from field
|
||
|
|
||
|
$content[$field["field_name"]] = $row[$field["field_name"]];
|
||
|
}
|
||
|
|
||
|
/*if a final level, hide_duplicates = True, and it is a duplicate,
|
||
|
make $field_content = "" and skip to display*/
|
||
|
$duplicate = false; //seed/reset
|
||
|
|
||
|
if ($last_content[$field["field_name"]] == $content[$field["field_name"]]) {
|
||
|
$duplicate = true;
|
||
|
}
|
||
|
|
||
|
//set last content for next comparison (if any)
|
||
|
$last_content[$field["field_name"]] = $content[$field["field_name"]];
|
||
|
|
||
|
if ($this->group_level === false
|
||
|
AND $duplicate === true
|
||
|
AND $field["hide_duplicates"] === true) {
|
||
|
|
||
|
$field_content = "";
|
||
|
|
||
|
//skipping formatting and linking
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// 4-1-5) set up formatting e.g. decimal places
|
||
|
|
||
|
$style = $this->getStyle($field["field_format"]);
|
||
|
$dp = $this->getDp($field["field_format"]);
|
||
|
$date_format = $this->getDateFormat($field["field_format"]);
|
||
|
|
||
|
//echo "<br>Field content before formatting is: " . $content[$field["field_name"]];
|
||
|
//echo "<br>Field array contains: " . print_r($field) . "<br>"; //check
|
||
|
$field_content = $this->myFormat($content[$field["field_name"]],
|
||
|
$style, $dp, $date_format);
|
||
|
|
||
|
// 4-1-6) put in link if required
|
||
|
if ($field["is_link"] === true) {
|
||
|
|
||
|
$field_content = "<a href=\"" . $field["link_href_start"] . rawurlencode($field_content) . $field["link_href_end"] . "\" " .
|
||
|
"title=\"" . $field["link_title_start"] . $field_content . $field["link_title_end"] . "\">" .
|
||
|
$field["link_text_start"] . $field_content . $field["link_text_end"] .
|
||
|
"</a>";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 4-1-7) display field
|
||
|
|
||
|
if ($this->group_level === true) {
|
||
|
$this->formatter->addColumn($field["field_label"], $field_label_class_html);
|
||
|
$this->formatter->addColumn($field_content, $field_class_html);
|
||
|
} else {
|
||
|
$this->formatter->addColumn($field_content, $field_class_html);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$this->formatter->endRow();
|
||
|
$this->add_headers = 0;
|
||
|
|
||
|
if ($this->group_level === true) { //a separate table for each group by level
|
||
|
$this->formatter->endTable();
|
||
|
}
|
||
|
|
||
|
|
||
|
//5-1) add additional grouping criteria to $grouping_criteria
|
||
|
|
||
|
//loop through all fields in level - add to grouping_criteria filter if new_group_by is True
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
|
||
|
if ($field["group_children_by"] != true) { //only process this field if adding to filter
|
||
|
continue;
|
||
|
}
|
||
|
$key = "`" . $field["field_name"] . "`";
|
||
|
$value = $row[$field["field_name"]];
|
||
|
|
||
|
if (strpos($field["field_format"],"num") === false) {
|
||
|
$value = $db->qstr($value);
|
||
|
}
|
||
|
$this->grouping_criteria[$key] = $value;
|
||
|
$this->grouping_aggregate[$key] = $field['field_aggregate'];
|
||
|
}
|
||
|
|
||
|
//echo "<br>The grouping_criteria are now set to: " . print_r($this->grouping_criteria) . "<br>"; //check */
|
||
|
|
||
|
if ($this->group_level === true) {
|
||
|
$this->intersperse($this->grouping_criteria,$this->grouping_aggregate);
|
||
|
if(strlen($this->lev_setting["class"]))
|
||
|
$this->formatter->write('</div>');
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// 6 DISPLAY TOTALS (only if a final level and only if one required)
|
||
|
|
||
|
/*any fields which have 'have_tot' equal True? Loop through them, and build array of field names.
|
||
|
If the array has any values, proceed (and pass on array to provide headstart building source query*/
|
||
|
|
||
|
if ($this->group_level === false) {
|
||
|
$this->addTotal($db);
|
||
|
$this->formatter->endTable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function addHeaderLabels ($heading)
|
||
|
{
|
||
|
if($this->add_headers>0) return;
|
||
|
$this->add_headers++;
|
||
|
|
||
|
$this->formatter->addTable($this->lev_setting["lev_table_class_html"], $heading);
|
||
|
$this->formatter->addRow();
|
||
|
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
// only display field if visible
|
||
|
if ($field['visible'] === False) {
|
||
|
continue; //skip this field
|
||
|
}
|
||
|
|
||
|
$field_label_class_html = $this->classHtml($field["field_label_class"],
|
||
|
$this->lev_setting["lev_label_class"],
|
||
|
$field["lev_label_class_also"]);
|
||
|
|
||
|
$field_width_html = $this->setWidth ($field["field_width"], $this->lev_setting["lev_field_width"]);
|
||
|
|
||
|
// c) display
|
||
|
$this->formatter->addColumn($field["field_label"], $field_label_class_html);
|
||
|
}
|
||
|
$this->formatter->endRow();
|
||
|
}
|
||
|
|
||
|
function addTotal (&$db)
|
||
|
{
|
||
|
// 0 ) check to see if totals are required for any of the fields >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||
|
// (and build SQL select statement for totals row)
|
||
|
|
||
|
$SQL_select_tot = '';
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
if ($field['has_tot'] === True) {
|
||
|
if ($SQL_select_tot == '') {
|
||
|
$SQL_select_tot =
|
||
|
"SELECT Sum(" . $field["field_name"] . ") AS `Tot_" . $field["field_name"] . "`" ;
|
||
|
} else {
|
||
|
$SQL_select_tot .=
|
||
|
", Sum(" . $field["field_name"] . ") AS `Tot_" . $field["field_name"] . "`";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($SQL_select_tot == '') {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$group_by = "";
|
||
|
if (count($this->grouping_criteria) > 0) {
|
||
|
$group_by = "GROUP BY ";
|
||
|
foreach ($this->grouping_criteria as $key=>$value) {
|
||
|
$group_by .= (($group_by === "GROUP BY ") ? $key : ", " . $key);
|
||
|
}
|
||
|
}
|
||
|
//echo "<br>Group by is now: " .$group_by;
|
||
|
|
||
|
$SQL_tot_filtered = $this->shuffleSQL("$SQL_select_tot FROM (" . $this->SQL_filtered .
|
||
|
") AS Source "); #$group_by"; //each key in grouping criteria
|
||
|
|
||
|
# echo "<br>The SQL tot filtered is: " . $SQL_tot_filtered . "<br>";
|
||
|
$result1 = $db->Execute($SQL_tot_filtered);
|
||
|
while (!$result1->EOF) {
|
||
|
$row = $result1->fields;
|
||
|
$result1->MoveNext();
|
||
|
|
||
|
$this->formatter->addRow();
|
||
|
|
||
|
foreach ($this->lev_fields as $field) {
|
||
|
if ($field["visible"] === False) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//must create class html here - it is a combination of field and level class settings
|
||
|
$field_tot_class_html = $this->classHtml($field["field_tot_class"],
|
||
|
$this->lev_setting["lev_tot_class"],
|
||
|
$field["lev_tot_class_also"]);
|
||
|
|
||
|
$field_width_html = $this->setWidth ($field["field_width"], $this->lev_setting["lev_field_width"]);
|
||
|
|
||
|
if ($field["has_tot"] === True) {
|
||
|
|
||
|
// 6-2-1-1) set up field content (whether a value or a format)
|
||
|
|
||
|
if ($field["tot_label"] != "") {
|
||
|
|
||
|
// 6-2-1-1-1) set up label
|
||
|
$field_content = $field["tot_label"];
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// 6-2-1-1-2) set up formatting e.g. decimal places (only run when a cell to display)
|
||
|
$field_tot = "Tot_" . $field["field_name"];
|
||
|
|
||
|
$field_content = $this->myFormat($row["$field_tot"],
|
||
|
$this->getStyle($field["field_tot_format"]),
|
||
|
$this->getDp($field["field_tot_format"]),
|
||
|
$this->getDateFormat($field["field_format"]));
|
||
|
}
|
||
|
|
||
|
// 6-2-1-2) display row
|
||
|
$this->formatter->addColumn($field_content, $field_tot_class_html);
|
||
|
} else {
|
||
|
|
||
|
// 6-2-2) display row
|
||
|
$this->formatter->addColumn(" ", $field_tot_class_html);
|
||
|
}
|
||
|
}
|
||
|
$this->formatter->endRow();
|
||
|
}
|
||
|
return true; //i.e. had totals
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* This is the base Level class, any and all types of rendered chunks MUST inherit from this.
|
||
|
*/
|
||
|
class Level_Base {
|
||
|
|
||
|
/**
|
||
|
* Add a user criteria to the WHERE clause
|
||
|
*/
|
||
|
function addFieldCriteria($sql, $bIsAggregate = false, $field = '')
|
||
|
{
|
||
|
require_once PATH_INCLUDES . 'pear/Compat/Function/stripos.php';
|
||
|
$this->lev_setting['SQL_criteria'] =
|
||
|
$this->addToFilter($this->lev_setting['SQL_criteria'],
|
||
|
$sql, $bIsAggregate);
|
||
|
|
||
|
if(strlen($this->lev_setting['SQL_order'])>0) {
|
||
|
$sql = $this->lev_setting['SQL_order'];
|
||
|
if( ($p=stripos($sql,'GROUP BY')) !== false) {
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$groupby = substr($sql,$p,$t[1]-$p);
|
||
|
if(stripos($groupby,$field)===false)
|
||
|
$sql = str_replace($groupby,$groupby.", {$field}",$sql);
|
||
|
}
|
||
|
}
|
||
|
$this->lev_setting['SQL_order'] = $sql;
|
||
|
} else {
|
||
|
$this->lev_setting['SQL_order'] = "GROUP BY ".$field;
|
||
|
}
|
||
|
|
||
|
if(isset($this->dataset)) {
|
||
|
for($i=0;$i<count($this->dataset);$i++) {
|
||
|
if(strlen($this->dataset[$i]['SQL_order'])>0) {
|
||
|
$sql = $this->dataset[$i]['SQL_order'];
|
||
|
if( ($p=stripos($sql,'GROUP BY')) !== false) {
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$groupby = substr($sql,$p,$t[1]-$p);
|
||
|
if(stripos($groupby,$field)===false)
|
||
|
$sql = str_replace($groupby,$groupby.", {$field}",$sql);
|
||
|
}
|
||
|
}
|
||
|
$this->dataset[$i]['SQL_order'] = $sql;
|
||
|
} else {
|
||
|
$this->dataset[$i]['SQL_order'] = "GROUP BY ".$field;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a sub-object to render beneath the current object
|
||
|
*/
|
||
|
function append (&$item)
|
||
|
{
|
||
|
$this->lev_items[] =& $item;
|
||
|
}
|
||
|
|
||
|
function addBreak ()
|
||
|
{
|
||
|
$this->lev_items[] = new Report_BreakAdaptor;
|
||
|
}
|
||
|
|
||
|
function addDiv($id)
|
||
|
{
|
||
|
$item = new Report_BreakAdaptor;
|
||
|
$item->id = $id;
|
||
|
$this->lev_items[] =& $item;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This calls all sub-objects of the current object to tell them to build their output
|
||
|
*/
|
||
|
function intersperse ($grouping_criteria, $grouping_aggregate)
|
||
|
{
|
||
|
if(isset($this->lev_items) && is_array($this->lev_items)) {
|
||
|
foreach ($this->lev_items as $item) {
|
||
|
#if(strlen($this->lev_setting['class']))
|
||
|
# $this->formatter->write('<div id="'.$this->lev_setting["class"].'">');
|
||
|
$c = $this->formatter->indent;
|
||
|
$item->display($grouping_criteria, $grouping_aggregate, $this->formatter);
|
||
|
$this->formatter->indent = $c;
|
||
|
#if(strlen($this->lev_setting["class"]))
|
||
|
# $this->formatter->write('</div>');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Build onto the SQL WHERE/HAVING clause
|
||
|
*/
|
||
|
function addToFilter ($full_criteria, $new_criterion, $aggregate = false)
|
||
|
{
|
||
|
/*
|
||
|
echo "<BR>";
|
||
|
echo "full_criteria = ".$full_criteria."<br>";
|
||
|
echo "new_criterion = ".$new_criterion."<br>";
|
||
|
echo "aggregate = ".$aggregate."<br>";
|
||
|
*/
|
||
|
$new_criterion = str_replace(" "," ",$new_criterion);
|
||
|
$new_criterion = str_replace("WHERE HAVING","HAVING",$new_criterion);
|
||
|
$t = "WHERE";
|
||
|
if($aggregate) {
|
||
|
$t = "HAVING";
|
||
|
}
|
||
|
if ($full_criteria == "") {
|
||
|
if(strpos($new_criterion,$t)!==false)
|
||
|
return $new_criterion;
|
||
|
else
|
||
|
return " $t " . $new_criterion;
|
||
|
break;
|
||
|
}
|
||
|
#echo "t:".$t."<br>fc:".$full_criteria."<br>nc:".$new_criterion."<BR>";
|
||
|
if (strpos($full_criteria, $t) === False && strpos($new_criterion, $t)===false) {
|
||
|
if($t == "WHERE") {
|
||
|
$r = " WHERE ".$full_criteria;
|
||
|
if(strlen($new_criterion))
|
||
|
$r .= " AND ".$new_criterion;
|
||
|
return $r;
|
||
|
} else {
|
||
|
return $full_criteria." $t " . $new_criterion;
|
||
|
}
|
||
|
} else if(strpos($full_criteria, $t)!==false && strpos($new_criterion, $t) !== false) {
|
||
|
$sql = $full_criteria . " AND " . substr($new_criterion, strpos($new_criterion,$t)+strlen($t));
|
||
|
$sql = str_replace("AND HAVING","HAVING",$sql);
|
||
|
#echo 'OUTPUT:'.$sql."<br>";
|
||
|
return $sql;
|
||
|
} else {
|
||
|
#echo "fc1:".$full_criteria."<br>nc:".$new_criterion."<BR>";
|
||
|
if(strncasecmp(trim($new_criterion),"having",6)==0)
|
||
|
return $full_criteria . ' '. $new_criterion;
|
||
|
else
|
||
|
return $full_criteria . " AND " . $new_criterion;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function find_next_sql_keyword($sql,$offset=0)
|
||
|
{
|
||
|
require_once PATH_INCLUDES . 'pear/Compat/Function/stripos.php';
|
||
|
$ret = false;
|
||
|
if(is_string($sql) && is_numeric($offset)) {
|
||
|
$arr = array(
|
||
|
'WHERE',
|
||
|
'GROUP BY',
|
||
|
'ORDER BY',
|
||
|
'LIMIT',
|
||
|
'HAVING'
|
||
|
);
|
||
|
$bFound = false;
|
||
|
foreach($arr as $k) {
|
||
|
if( ($t=stripos($sql,$k,$offset)) !== false) {
|
||
|
if($ret === false) {
|
||
|
$ret = array($k,$t);
|
||
|
$bFound = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if($bFound == false) {
|
||
|
$ret = array('',strlen($sql));
|
||
|
}
|
||
|
}
|
||
|
return $ret;
|
||
|
}
|
||
|
|
||
|
function shuffleSQL($sql, $groupBy='')
|
||
|
{
|
||
|
require_once PATH_INCLUDES . 'pear/Compat/Function/stripos.php';
|
||
|
if( ($p=stripos($sql,'HAVING')) !== false) {
|
||
|
# found a having clause
|
||
|
$leading = '';
|
||
|
$having = '';
|
||
|
$groupby = '';
|
||
|
$orderby = '';
|
||
|
$limit = '';
|
||
|
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$having = substr($sql,$p,$t[1]-$p);
|
||
|
$sql = str_replace($having,'',$sql);
|
||
|
}
|
||
|
if( ($p=stripos($sql,'GROUP BY')) !== false) {
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$groupby = substr($sql,$p,$t[1]-$p).$groupBy;
|
||
|
$sql = str_replace($groupby,'',$sql);
|
||
|
}
|
||
|
}
|
||
|
if( ($p=stripos($sql,'ORDER BY')) !== false) {
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$orderby = substr($sql,$p,$t[1]-$p);
|
||
|
$sql = str_replace($orderby,'',$sql);
|
||
|
}
|
||
|
}
|
||
|
if( ($p=stripos($sql,'LIMIT')) !== false) {
|
||
|
if( ($t=$this->find_next_sql_keyword($sql,$p+1)) !== false) {
|
||
|
$limit = substr($sql,$p,$t[1]-$p);
|
||
|
$sql = str_replace($limit,'',$sql);
|
||
|
}
|
||
|
}
|
||
|
#echo "having=$having<br>groupby=$groupby<br>orderby=$orderby<br>limit=$limit<br>";
|
||
|
$sql .= $groupby.' '.$having.' '.$orderby.' '.$limit;
|
||
|
}
|
||
|
return $sql;
|
||
|
}
|
||
|
|
||
|
|
||
|
function makeCondition ($condition, $row, $fields)
|
||
|
{
|
||
|
//replace bracketed text with data from field in row with same name
|
||
|
//numeric data does not need to be unquoted as long as == is used instead of ===
|
||
|
//date data must be wrapped in strtotime on both sides of comparison to work (NB Unix time 1970 onwards only)
|
||
|
//replace brackets with PHP code then use eval to run generated string as PHP code
|
||
|
|
||
|
$condition = str_replace('[','$row[\'',$condition);
|
||
|
$condition = str_replace(']','\']',$condition);
|
||
|
$condition = "if($condition){\$condition_met=True;}else{\$condition_met=False;}";
|
||
|
//echo "<br>Test expression as generated: $condition";//check
|
||
|
eval($condition);
|
||
|
|
||
|
return $condition_met;
|
||
|
}
|
||
|
|
||
|
function setIndent ($indent)
|
||
|
{
|
||
|
return $this->formatter->setIndent($indent);
|
||
|
}
|
||
|
|
||
|
function myFormat ($value, $style, $dp, $date_format)
|
||
|
{
|
||
|
switch ($style) {
|
||
|
|
||
|
case "upper":
|
||
|
|
||
|
return strtoupper($value);
|
||
|
break;
|
||
|
|
||
|
case "perc":
|
||
|
|
||
|
return sprintf("%01." . $dp . "f", $value) . "%";
|
||
|
break;
|
||
|
|
||
|
case "dol":
|
||
|
|
||
|
return "$" . number_format($value, $dp);
|
||
|
break;
|
||
|
|
||
|
case "num":
|
||
|
|
||
|
return number_format($value, $dp);;
|
||
|
break;
|
||
|
|
||
|
case "date":
|
||
|
if ($value != "") {
|
||
|
/*echo "Date format: " . $date_format . ";
|
||
|
Value: " . $value . "Date: " . date($date_format, strtotime($value)); //check*/
|
||
|
return date($date_format, $value);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
return $value;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getStyle ($format)
|
||
|
{
|
||
|
$field_format = explode(",", $format);
|
||
|
return $field_format[0];
|
||
|
}
|
||
|
|
||
|
function getDp ($format)
|
||
|
{
|
||
|
$field_format = explode(",", $format);
|
||
|
return (count($field_format) > 1 ? $field_format[1] : 0);
|
||
|
}
|
||
|
|
||
|
function getDateFormat ($format)
|
||
|
{
|
||
|
$field_format = explode(",", $format);
|
||
|
return (count($field_format) > 2 ? $field_format[2] : "m/d/Y");
|
||
|
}
|
||
|
|
||
|
function setWidth ($field_width, $level_field_width)
|
||
|
{
|
||
|
$width = (($field_width != "") ? $field_width : $level_field_width);
|
||
|
return (($width != "") ? " width='" . $width . "'" : "" );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This is worthless junk from the original author, should be refactored
|
||
|
*/
|
||
|
function classHtml ($field_class, $lev_class, $both = False)
|
||
|
{
|
||
|
if(is_a($field_class,'ReportStyle'))
|
||
|
return $field_class;
|
||
|
if(is_a($lev_class,'ReportStyle'))
|
||
|
return $lev_class;
|
||
|
if ($field_class == "" AND $lev_class == "") { //nothing to set
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
switch ($both) {
|
||
|
|
||
|
case true: //use both classes
|
||
|
|
||
|
return "$field_class $lev_class";
|
||
|
break;
|
||
|
|
||
|
case false: //only use on class (field takes precedence over level)
|
||
|
|
||
|
if ($field_class != '') {
|
||
|
return $field_class;
|
||
|
} else {
|
||
|
return $lev_class;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
?>
|