KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

Sum of all values a collum on Excel package #472

Open Gustavo Fraga opened this topic on on Sep 18, 2018 - 2 comments

Gustavo Fraga commented on Sep 18, 2018

How append a row containing a sum of all values of the respective column?

David Winterburn commented on Sep 20, 2018

Hi Gustavo,

We could do that with the latest development version of process Map which unfortunately hasn't been released yet. Please open the file processes/Map.php and replace its content with this:

<?php
/**
 * This file contains class to map data value to another.
 *
 * @author KoolPHP Inc (support@koolphp.net)
 * @link https://www.koolphp.net
 * @copyright KoolPHP Inc
 * @license https://www.koolreport.com/license#mit-license
 */

/* Usage
    ->pipe(new Map(array(
        '{value}' => function ($row, $metaData, $index, $mapState) {
            return $newRows;
            return ['{rows}' => $newRows, '{state}' => $newMapState];
        },
        '{meta}' => function ($metaData) {
            return $newMeta;
        },
        '{end}' => function ($count, $mapState) {
            $avg = Util::get($mapState, 'sum', []);
            foreach ($avg as $i => $v) {
                $avg[$i] = is_numeric($v) ? $v / $count : 'Average';
            }

            $mapState['avg'] = $avg;
            return $mapState;
        },
    )));
 *
 *
 */

namespace koolreport\processes;

use \koolreport\core\Process;
use \koolreport\core\Utility as Util;

class Map extends Process
{
    protected $metaSent = false;
    protected $metaData;
    protected $newMeta;
    protected $index = 0;
    protected $mapState = [];

    public function onInit()
    {
        $func = Util::get($this->params, '{init}', null);
        if (is_callable($func)) {
            $this->mapState = $func($data);
        }
    }

    public function receiveMeta($metaData, $source)
    {
        $this->streamingSource = $source;
        $this->newMeta = $this->metaData = $metaData;
        $func = Util::get($this->params, '{meta}', null);
        if (is_callable($func)) {
            $this->newMeta = $func($metaData);
        }
    }

    protected function guessType($value)
    {
        $map = array(
            "float" => "number",
            "double" => "number",
            "int" => "number",
            "integer" => "number",
            "bool" => "number",
            "numeric" => "number",
            "string" => "string",
        );
        $type = strtolower(gettype($value));

        foreach ($map as $key => $value) {
            if (strpos($type, $key) !== false) {
                return $value;
            }
        }

        return "unknown";
    }

    protected function to2DArray($arr)
    {
        if (empty($arr) || !is_array($arr)) {
            return [];
        }
        if (count($arr) == count($arr, COUNT_RECURSIVE)) {
            return [$arr];
        }
        return $arr;
    }

    protected function onInput($row)
    {
        $func = Util::get($this->params, '{value}', null);
        if (is_callable($func)) {
            $return = $func($row, $this->metaData, 
                $this->index, $this->mapState);
            
            if (is_array($return) && (array_key_exists('{rows}', $return) || 
                array_key_exists('{state}', $return))) {
                $newRows = Util::get($return, '{rows}', []);
                $this->mapState = Util::get($return, '{state}', $this->mapState);
            } else {
                $newRows = $return;
            }
            $newRows = $this->to2DArray($newRows);
            if (!$this->metaSent) {
                $colMetas = $this->newMeta['columns'];
                $newRow = Util::get($newRows, 0, []);
                foreach (array_keys($newRow) as $newCol) {
                    if (!isset($colMetas[$newCol])) {
                        $type = $this->guessType($newRow[$newCol]);
                        $colMetas[$newCol] = ['type' => $type];
                    }
                }
                $this->newMeta['columns'] = $colMetas;
                $this->sendMeta($this->newMeta);
                $this->metaSent = true;
            }
            foreach ($newRows as $row) {
                $this->next($row);
            }
        } else {
            if (!$this->metaSent) {
                $this->sendMeta($this->newMeta);
                $this->metaSent = true;
            }
            $this->next($row);
        }
        $this->index++;
    }

    public function endInput($source)
    {
        if (!$this->metaSent) {
            $this->sendMeta($this->newMeta);
        }
        $func = Util::get($this->params, '{end}', null);
        if (is_callable($func)) {
            $newRows = $func($this->index, $this->mapState);
            $newRows = $this->to2DArray($newRows);
            foreach ($newRows as $row) {
                $this->next($row);
            }
        }
        parent::endInput($source);
    }
}

Then in your report, apply the following:

use \koolreport\core\Utility as Util;

...
->pipe(new Map([
	'{value}' => function($row, $meta, $index, $mapState) {
		$sum = Util::init($mapState, 'total', []);
		foreach ($row as $c => $v) {
			Util::init($sum, $c, 0);
			//Change the following condition (is_numeric) for columns that you want to sum on
			//$c is column name, $v is row[column name]'s value
			$sum[$c] = is_numeric($v) ? $sum[$c] + $v : 'Total sum';
		}
		$mapState['total'] = $sum;
		return ['{rows}' => $row, '{state}' => $mapState];
		
	},
	'{end}' => function($count, $mapState) {
		return $mapState['total'];
	},
]))
->pipe($this->dataStore('dataForExcelExport'));

These steps should add a sum row for your columns. Please let us know if you have any question. Thanks!

Gustavo Fraga commented on Sep 24, 2018

Hi, thanks for attention! This solved the problem... I will go implement the solution and if necessary, i will ask for help again!

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
help needed
solved
suggestion

Excel