Location: PHPKode > projects > THINi Reports > THINiReports-0.1.1/THINiReport.class.php
<?php
class THINiReport
{

    public $Data_Assoc;
    public $Data_Grouped;
    public $Data_Grouped_HTML;
    public $Groups = array();
    public $Group_Count = 0;
    public $Grouped_Column_Count;
    public $Column_Headers = array();
    public $Column_Widths = false;
	
	public $ShowSub = array();
	public $Subtotals = array();
    
    
    public function __construct()
    {
    }
    
    public function __destruct()
    {
    }

    public function Load_Data($data)
    {
        $this->Data_Assoc = $data;
        $this->Column_Headers = array_keys($this->Data_Assoc[0]);
    }
    
    
    /*
     * Group_Data($groups)
     * Organises an associative array into groupings of common data
     * $groups, if specified, is an array of column headers for which data should be grouped
     * groupings are ordered by their array index.
     * ToDo: If no groupings are specified search the array for recurring data and guess groupings according to number of occurences of given values (number of distinct values in column)
     */
    public function Group_Data($groups = false)
    {
        if(!$groups)
        {
            $this->Determine_Groups(3);
        }
        else
        {
            $this->Groups = $groups;
        }
        
        $this->Group_Count = count($this->Groups);

        //An in-elegant way of populating a grouping array of up to 6 dimensions. Improvements on a postcard please!
        foreach($this->Data_Assoc as $row_number => $row_data)
        {
            $trimmed_data = $row_data;
            for($i = 0; $i < $this->Group_Count; $i ++)
            {
                unset($trimmed_data[$this->Groups[$i]]);
            }
            switch($this->Group_Count)
            {
                case 1:
                    $data_grouped[$row_data[$this->Groups[0]]][] = $trimmed_data;
                break;
                case 2:
                    $data_grouped[$row_data[$this->Groups[0]]][$row_data[$this->Groups[1]]][] = $trimmed_data;
                break;
                case 3:
                    $data_grouped[$row_data[$this->Groups[0]]][$row_data[$this->Groups[1]]][$row_data[$this->Groups[2]]][] = $trimmed_data;
                break;
                case 4:
                    $data_grouped[$row_data[$this->Groups[0]]][$row_data[$this->Groups[1]]][$row_data[$this->Groups[2]]][$row_data[$this->Groups[3]]][] = $trimmed_data;
                break;
                case 5:
                    $data_grouped[$row_data[$this->Groups[0]]][$row_data[$this->Groups[1]]][$row_data[$this->Groups[2]]][$row_data[$this->Groups[3]]][$row_data[$this->Groups[4]]][] = $trimmed_data;
                break;
                case 6:
                    $data_grouped[$row_data[$this->Groups[0]]][$row_data[$this->Groups[1]]][$row_data[$this->Groups[2]]][$row_data[$this->Groups[3]]][$row_data[$this->Groups[4]]][$row_data[$this->Groups[5]]][] = $trimmed_data;
                break;
            }
        }
        $this->Column_Headers = array_keys($trimmed_data);
        $this->Grouped_Column_Count = count($trimmed_data);
        $this->Data_Grouped = $data_grouped;
    }

    public function Determine_Groups($max_groups = 3)
    {
        /*
        //Until this function is written, use the first n ($max_groups) columns as the groupings
        for($i = 0; $i < $max_groups; $i ++)
        {
            $groups[] = $this->Column_Headers[$i];
        }
        $this->Groups = $groups;
        */

        //create an array of columns
        foreach($this->Data_Assoc as $row_number => $row_data)
        {
            foreach($row_data as $column_header => $field_value)
            {
                $g[$column_header][$field_value] = 1;
            }
        }
        
        //count distinct values
        foreach($g as $k => $v)
        {
            $x[$k] = count($g[$k]);
        }
        //print_r($x);

        //sort by lowest number of distinct columns (most recurrent values)
        asort($x);
        reset($x);

        //populate groups array in order
        foreach($x as $k => $v)
        {
            $groups[] = $k;
        }

        //trim array to max number of groupings
        $this->Groups = array_slice($groups, 0, $max_groups);

    }
    public function Assoc_2_XML($data, $i = ''){

        $xml = '';
        foreach($data as $k => $v){
            $k = is_int($k) ? 'row' : $k;
            $xml .= is_array($v) ? "$i<$k>\n".$this->Assoc_2_XML($v, "$i ")."$i</$k>\n" : "$i<$k>$v</$k>\n";
        }
        return $xml;

    }
    
    public function Display_Group_Divs($a, $d = 0, $show_count = true, $parent = false)
    {
        //group headers should be h1 ~ h6
        $h = ($d < 6) ? ($d + 1) : 6;

        //if the arrays elements, elements are also arrays, we are displaying a grouping
        if(is_array(current(current($a))))
        {
            //display header and contents for each element
            foreach($a as $k => $v)
            {
                $html .= "<h$h>".trim($k)."</h$h>\n";
                $html .= "<div class='group'>\n";
                $html .= $this->Display_Group_Divs($v, ($d + 1), $show_count, $k);
                
                //display the row count for this grouping (currently only works for last grouping)
                if($show_count && !is_array(current(current($v))))
                {
                    $html .= "<div class='group'>\n";
                    $html .= "<strong>Count: ".count($v)."</strong>\n";
                    //$html .= "<br style='clear: both;' />\n";
					
					//if there is a subtotal array for this grouping level
					if(is_array($this->Subtotals[$d][$k]))
					{
						foreach($this->Subtotals[$d][$k] as $k_st => $v_st)
						{
							//if subtotaling is explicitly on for this level and column
							if(is_array($this->ShowSub[$k_st]) && in_array($d, $this->ShowSub[$k_st]))
							{
								$html .= "| <strong>$k_st: $v_st</strong>\n";
							}
						}
					}
					
                    $html .= "</div>\n";
                }
                
                $html .= "<br style='clear: both;' />\n";
                
                $html .= "</div>\n";
            }
        }
        //else we are displaying the data fields
        else
        {
            //display each field
            foreach($a as $k => $v)
            {
                $class = ($k & 1) ? 'field_odd' : 'field_even';
                
                foreach($v as $fk => $fv)
                {
                    //check for column width settings
                    $column_width = ($this->Column_Widths) ? " style='width: ".$this->Column_Widths[$fk]."px;'" : '';
                    
                    $html .= "<div class='$class'$column_width><a title='$fk'>$fv</a></div>\n";
					
					//if subtotaling is explicitly on for this level and column
					if(is_numeric($fv) && is_array($this->ShowSub[$fk]) && in_array($d - 1, $this->ShowSub[$fk]))
					{
						$this->Subtotals[($d - 1)][$parent][$fk] = (isset($this->Subtotals[($d - 1)][$parent][$fk])) ? ($this->Subtotals[($d - 1)][$parent][$fk] + $fv) : $fv;
					}
                }
                $html .= "<br style='clear: both;' />\n";
            }
        }
        $this->Data_Grouped_HTML = $html;
        return $html;
    }

    function Column_Headers()
    {
        for($i = 0; $i < $this->Group_Count; $i ++)
        {
            $html .= "<div class='group'>\n";
            if($i == ($this->Group_Count - 1))
            {
                foreach($this->Column_Headers as $ch)
                {
                    //check for column width settings
                    $column_width = ($this->Column_Widths) ? " style='width: ".$this->Column_Widths[$ch]."px;'" : '';
                    
                    $html .= "<div class='field'$column_width>$ch</div>\n";
                }
                $html .= "<br style='clear: both;' />\n";
            }
        }
        for($i = 0; $i < $this->Group_Count; $i ++)
        {
            $html .= "</div>\n";
        }
        return $html;
    }
    
    /*
     * Random_String([$length])
     * Generates and returns a random string of lowercase characters
     * $length, if specified will determine the length of the string
     * $length defaults to a random number between 3 and 6
     */
    public function Random_String($length = false)
    {
        $l = ($l) ? intval($l) : rand(3, 9);
        $string = '';
        for($i = 0; $i < $length; $i ++)
        {
            $string .= chr(rand(97, 98));
        }
        return $string;
    }
    
    /*
     * Random_Data([int $aCols] [, int $nCols])
     * Generates and returns an associative array of random data
     * $rows is the number of rows to generate. Defaults to 50
     * $aCols is the number of columns with alphabetic strings. Defaults to 6
     * $nCols is the number of columns with numeric data. Defaults to 6
     */
    public function Random_Data($rows = 50, $aCols = 6, $nCols = 6)
    {
    
        for($r = 0; $r < $rows; $r ++)
        {
        
            //columns with alpha data
            for($a = 65; $a < (65 + $aCols); $a ++)
            {
                $data[$r]['col'.chr($a)] = $this->Random_String(2);
            }

            //columns with numeric data
            for($n = 1; $n <= $nCols; $n ++)
            {
                $data[$r]['col'.$n] = rand(1, 200);
            }
        }
        $this->Data_Assoc = $data;
        $this->Column_Headers = array_keys($this->Data_Assoc[0]);
        return $data;
    }

    public function Less_Random_Data()
    {
        $csv = file('lib/assets/uk.csv');
        foreach($csv as $line){
            $l = explode(',', $line);
            $data[] = array('Postcode'=>$l[0], 'Town'=>$l[1], 'County'=>$l[2], 'ItemA'=>rand(100, 1000), 'ItemB'=>rand(100, 1000));
        }
        $this->Data_Assoc = array_slice($data, 0, 250);
        $this->Column_Headers = array_keys($this->Data_Assoc[0]);
        return $this->Data_Assoc;
    }
}


?>
Return current item: THINi Reports