Map Process with State

Sum data rows' value with map's state.

productNamedollar_sales
1937 Lincoln Berline 3,726
1936 Mercedes-Benz 500K Special Roadster 1,768
1952 Alpine Renault 1300 5,572
1962 LanciaA Delta 16V 5,026
1958 Setra Bus 3,284
1940 Ford Pickup Truck 3,308
1926 Ford Fire Engine 1,283
1913 Ford Model T Speedster 2,489
1934 Ford V8 Coupe 2,164
18th Century Vintage Horse Carriage 2,173

->pipe(new Map([
    '{value}' => function($row, $meta, $index, $mapState) {
        $numTopRows = 2;
        //If a row is among the first 2 rows
        if ($index < $numTopRows) {
            $mappedRows = [$row];
            //return it to send to next process or datastore
            return ['{rows}' => $mappedRows]; 
        }
        //Otherwise,
        //initialise a key of this Map's state to use for sum
        $sum = Util::init($mapState, 'sumOthers', []);
        foreach ($row as $columnName => $value) {
            Util::init($sum, $columnName, 0);
            //if column name = 'dollar_sales', sum it
            $sum[$columnName] = $columnName === 'dollar_sales' ? 
                $sum[$columnName] + $value : 'Other Customers';
        }
        //Save the sum to this Map's state
        $mapState['sumOthers'] = $sum;
        $mappedRows = [];
        //Skip rows after the first 2 rows (they won't be sent to next process or datastore) 
        //return this Map's state to save it
        return ['{rows}' => $mappedRows, '{state}' => $mapState];
        
    },
    '{end}' => function($count, $mapState) {
        //After all rows had been sent
        //retrieve this Map's state and send it at the end of Map process
        $rowsToSend = [$mapState['sumOthers']];
        return $rowsToSend;
    },
]))
productNamedollar_sales
1937 Lincoln Berline 3,726
1936 Mercedes-Benz 500K Special Roadster 1,768
Other Customers 25,300

This example shows how to use mapstate of Map process KoolReport. The mapstate will let you remember state of your calculation. The mapState will be extremely useful when you use Map process to calculate aggregated values.

This process is advanced way to transform your data. Using Map process, you can controls both meta data of data flow as well as the values. Virtually you can do all most everything with this process. So instead of driving your data through various processes, you may just use Map with custom code to reach same result. Of course, since it is more powerful and flexible, it is a little more difficult to use in comparing to other processes. In return, it will make your code shorter and faster and do exactly what you want to do.

In the "{value}" property, you define a custom function which received $row as parameters. Each row of data will be sent to your function before it comes back to the mainstream. Note that the function return an array of rows. If you want to add more rows to data stream, you can do so.

The "{meta}" is property which is basically a function that received old meta data. You may process meta data then return a new meta data. Or if there is no change in meta data, you will return exactly the old meta there.

<?php
require_once "MyReport.php";

$report = new MyReport;
$report->run()->render();
<?php
//Step 1: Load KoolReport
require_once "../../../../koolreport/autoload.php";
use \koolreport\processes\Limit;
use \koolreport\processes\Sort;
use \koolreport\processes\Map;
use \koolreport\processes\OnlyColumn;
use \koolreport\processes\ColumnMeta;
use \koolreport\cube\processes\SuperCube;
use \koolreport\core\Utility as Util;

//Step 2: Creating Report class
class MyReport extends \koolreport\KoolReport
{
    function settings()
    {
        return array(
            "dataSources" => array(
                "dollarsales"=>array(
                    'filePath' => '../../../databases/customer_product_dollarsales2.csv',
                    'fieldSeparator' => ';',
                    'class' => "\koolreport\datasources\CSVDataSource"      
                ), 
            )
        );
    }
  
    function setup()
    {
        $node = $this->src('dollarsales')
        ->pipe(new OnlyColumn([
            'productName', 'dollar_sales'
        ]))
        ->pipe(new ColumnMeta([
            'dollar_sales' => ['type' => 'number']
        ]))
        ->pipe(new Limit(array(
            10, 0
        )))
        ;

        $node->pipe($this->dataStore('salesProduct'));

        $node
        ->pipe(new Map([
            '{value}' => function($row, $meta, $index, $mapState) {
                $numTopRows = 2;
                //If a row is among the first 2 rows
                if ($index < $numTopRows) {
                    $mappedRows = [$row];
                    //return it to send to next process or datastore
                    return ['{rows}' => $mappedRows]; 
                }
                //Otherwise,
                //initialise a key of this Map's state to use for sum
                $sum = Util::init($mapState, 'sumOthers', []);
                foreach ($row as $columnName => $value) {
                    Util::init($sum, $columnName, 0);
                    //if column name = 'dollar_sales', sum it
                    $sum[$columnName] = $columnName === 'dollar_sales' ? 
                        $sum[$columnName] + $value : 'Other Customers';
                }
                //Save the sum to this Map's state
                $mapState['sumOthers'] = $sum;
                $mappedRows = [];
                //Skip rows after the first 2 rows (they won't be sent to next process or datastore) 
                //return this Map's state to save it
                return ['{rows}' => $mappedRows, '{state}' => $mapState];
                
            },
            '{end}' => function($count, $mapState) {
                //After all rows had been sent
                //retrieve this Map's state and send it at the end of Map process
                $rowsToSend = [$mapState['sumOthers']];
                return $rowsToSend;
            },
        ]))
        ->pipe($this->dataStore('salesProductMap'));

    }
}
<?php
use \koolreport\datagrid\DataTables;
use \koolreport\morris_chart;
use \koolreport\sparklines;
use \koolreport\widgets\google;
use \koolreport\widgets\koolphp\Table;
?>


<div class="report-content">
    <div class="text-center">
        <h1>Map Process with State</h1>
        <p class="lead">
            Sum data rows' value with map's state.
        </p>
    </div>

    <?php
        $ds = $this->dataStore('salesProduct');
        Table::create(array(
            "dataSource" => $ds,
        ));
    ?>

    <i class="fa fa-arrow-down" style="font-size:24px;"></i>
    <pre style="font-weight:bold"><code>
->pipe(new Map([
    '{value}' => function($row, $meta, $index, $mapState) {
        $numTopRows = 2;
        //If a row is among the first 2 rows
        if ($index < $numTopRows) {
            $mappedRows = [$row];
            //return it to send to next process or datastore
            return ['{rows}' => $mappedRows]; 
        }
        //Otherwise,
        //initialise a key of this Map's state to use for sum
        $sum = Util::init($mapState, 'sumOthers', []);
        foreach ($row as $columnName => $value) {
            Util::init($sum, $columnName, 0);
            //if column name = 'dollar_sales', sum it
            $sum[$columnName] = $columnName === 'dollar_sales' ? 
                $sum[$columnName] + $value : 'Other Customers';
        }
        //Save the sum to this Map's state
        $mapState['sumOthers'] = $sum;
        $mappedRows = [];
        //Skip rows after the first 2 rows (they won't be sent to next process or datastore) 
        //return this Map's state to save it
        return ['{rows}' => $mappedRows, '{state}' => $mapState];
        
    },
    '{end}' => function($count, $mapState) {
        //After all rows had been sent
        //retrieve this Map's state and send it at the end of Map process
        $rowsToSend = [$mapState['sumOthers']];
        return $rowsToSend;
    },
]))</code></pre>
    <i class="fa fa-arrow-down" style="font-size:24px;"></i>
    <div style="margin-top:20px;">

    <?php
    $ds = $this->dataStore('salesProductMap');
    Table::create(array(
        "dataSource" => $ds,
    ));
    ?>

    <?php
        google\BarChart::create(array(
            "dataStore" => $this->dataStore('salesProductMap'),
            "options" => array(
                'title' => 'Product Sales',
                'isStacked' => true,
            ),
            "width" => '100%',
            // 'height'=>'400px',
        ));
    ?>

</div>

customerNameproductNameproductLineorderDateorderDayorderMonthorderYearorderQuarterdollar_sales
Vitachrome Inc. 1937 Lincoln Berline Vintage Cars 2003-01-10 00:00:00 10 1 2003 1 3726.45
Vitachrome Inc. 1936 Mercedes-Benz 500K Special Roadster Vintage Cars 2003-01-10 00:00:00 10 1 2003 1 1768.3300000000002
Baane Mini Imports 1952 Alpine Renault 1300 Classic Cars 2003-01-29 00:00:00 29 1 2003 1 5571.8
Baane Mini Imports 1962 LanciaA Delta 16V Classic Cars 2003-01-29 00:00:00 29 1 2003 1 5026.14
Baane Mini Imports 1958 Setra Bus Trucks and Buses 2003-01-29 00:00:00 29 1 2003 1 3284.28
Baane Mini Imports 1940 Ford Pickup Truck Trucks and Buses 2003-01-29 00:00:00 29 1 2003 1 3307.5
Baane Mini Imports 1926 Ford Fire Engine Trucks and Buses 2003-01-29 00:00:00 29 1 2003 1 1283.48
Baane Mini Imports 1913 Ford Model T Speedster Vintage Cars 2003-01-29 00:00:00 29 1 2003 1 2489.13
Baane Mini Imports 1934 Ford V8 Coupe Vintage Cars 2003-01-29 00:00:00 29 1 2003 1 2164.4
Baane Mini Imports 18th Century Vintage Horse Carriage Vintage Cars 2003-01-29 00:00:00 29 1 2003 1 2173

What People Are Saying

"KoolReport helps me very much in creating data report for my corporate! Keep up your good work!"
-- Alain Melsens

"The first use of your product. I was impressed by its easiness and powerfulness. This product is a great and amazing."
-- Dr. Lew Choy Onn

"Fantastic framework for reporting!"
-- Greg Schneider

Download KoolReport