Cakephp 3 chart

hello World,

i would like to know how to incorporate chart views into Cakehp 3,

this is a sample chart link http://gionkunz.github.io/chartist-js/

my apologies first as i don’t know what to show from the controller or template as hope that someone can show some ropes of what are the steps i need to prepare

i got an Orders Controller which recorded transactions, from there how can i start to dig on?

        $series = $this->Orders->find('list', [
        'keyField' => 'month',
        'valueField' => 'price',
        'fields'=>[
            'month' => 'MONTHNAME(created_at)',
            'price' => 'SUM(price)'
        ],
        'group' => ['month'],
        'order'=>['MONTHNAME(created_at)'=>'ASC'],
        ])
	->where(['user_id' => $this->authUser['id']])
	->toArray();

      $months = json_encode(array_keys($series));
      $amounts = json_encode(array_values($series));

    $this->set('months', $months);
    $this->set('amounts', $amounts);
	
$this->set(compact('series'));

The View Page to show dynamic chart how am i going to do the setting?

view.ctp

   <div class="widget-content tab-content bg-white p-20">
                <div class="ct-chart tab-pane active" id="scoreLineToDay"></div>

            
                <script>
                    new Chartist.Line('.ct-chart', {
                        labels: [<?= json_encode($months) ?>],
                        series: [
                            [<?= json_encode($amounts) ?>]
                        ]
                    }, {
                        low: 0,
                        showArea: true
                    });
                </script>


                <div class="ct-chart tab-pane" id="scoreLineToWeek"></div>
                <div class="ct-chart tab-pane" id="scoreLineToMonth"></div>

i added the script in the view.ctp in the way, is this correct? as the view is not showing the updated chart…

Hi,

You have to add your js script in your layout or combined JS and after add your hml/js code in your template file.

Controller should only prepare data and pass it to view

hi Erwane,

thanks for your message :grinning: :grinning: :grinning:,
yes, i have tried added the script to the template.ctp

  <div class="col-12" id="ecommerceChartView">
        <div class="card card-shadow">
            <div class="card-header card-header-transparent py-20">
                <div class="btn-group dropdown">
                    <a href="#" class="text-body dropdown-toggle blue-grey-700" data-toggle="dropdown">PRODUCTS SALES</a>
                    <div class="dropdown-menu animate" role="menu">
                        <a class="dropdown-item" href="#" role="menuitem">Sales</a>
                        <a class="dropdown-item" href="#" role="menuitem">Total sales</a>
                        <a class="dropdown-item" href="#" role="menuitem">profit</a>
                    </div>
                </div>
                <ul class="nav nav-pills nav-pills-rounded chart-action">
                    <li class="nav-item"><a class="active nav-link" data-toggle="tab" href="#scoreLineToDay">Day</a></li>
                    <li class="nav-item"><a class="nav-link" data-toggle="tab" href="#scoreLineToWeek">Week</a></li>
                    <li class="nav-item"><a class="nav-link" data-toggle="tab" href="#scoreLineToMonth">Month</a></li>
                </ul>
            </div>
            <div class="widget-content tab-content bg-white p-20">
                <div class="ct-chart tab-pane active" id="scoreLineToDay"></div>
                <div class="ct-chart tab-pane" id="scoreLineToWeek"></div>
                <div class="ct-chart tab-pane" id="scoreLineToMonth"></div>
            </div>
        </div>
    </div>

from the chart there’s display of Day, Week and Month sales chart

this is the template after generated,

The Order Controller, based on what i’ve learnt, i managed to get total figure based on sum only

	$sales = $this->Orders->find();
	$total = $sales->select(['amount' => $sales->func()->sum('price')])
            ->where(['user_id' => $this->authUser['id']])
	->first();
    $orders = $this->paginate($this->Orders->find()->where(['user_id' => $this->authUser['id']]));

   $this->set (['total'=>$total->amount]);
   $this->set(compact('orders'));

in the template.ctp. i managed to show total sales figure of USD23

    <class="font-size-40 font-weight-100">USD <?= $total ?>

In the Orders entity, the structure contains

   protected $_accessible = [
    'user_id' => true,
    'first_name' => true,
    'last_name' => true,
    'amount' => true,
    'created_at' => true,
    'updated_at' => true,
    'user' => true,
    'order_products' => true,

];

}

how do i code in the controller so that at the template can show day, week or month sales?

thank you and best regards

It’s not a CakePHP question :wink:

The documentation of your chart JS library say :

new Chartist.Line('.ct-chart', {
  labels: [1, 2, 3, 4, 5, 6, 7, 8],
  series: [
    [5, 9, 7, 8, 5, 3, 5, 4]
  ]
}, {
  low: 0,
  showArea: true
});

So, you have to generate your series in your Controller, from your Model then pass this array to view (with set).
In view, write your JS script or set global json variable :

<script>
    let series = <?= json_encode($series) ?>;
</script>

where $series is the array set in controller.

in the Controller, how do i write in order to generate the series? is there any link or reference where i can learn how to write it out?

what i can think of now is

 $series = $this->Orders->find();  

and that’s all…

i tried to read this link https://discourse.cakephp.org/t/cakephp3-any-suggestions-for-creating-line-graphs/710 but its too deep for me to understand… :sweat_smile: :sweat_smile: :sweat_smile:

hi, Erwane,

i found something just now and tried to blend into Controller, but yet successful

    $series = $this->Orders->find('list', [
        'keyField' => 'series',
        'valueField' => 'price',
        'fields'=>[
            'series' => 'MONTHNAME(created_at)',
            'price' => 'SUM(price)'
        ],
        'group' => ['series'],
        // 'order'=>['MONTH(created_at)'=>'ASC'],
    ])
	->where(['user_id' => $this->authUser['id']])
	->toArray();

    $months = json_encode(array_keys($series));
    $amounts = json_encode(array_values($series));

    $this->set('months', $months);
    $this->set('amounts', $amounts);
	
	$this->set(compact('series'));

is this something like that that i need to write to generate the series?

the view template.ctp, is this the way of how to create the chart?

 <script>

  series = <?= json_encode($series) ?>;

 new Chartist.Line('.ct-chart', {
 labels: [1, 2, 3, 4, 5, 6, 7, 8],
 series: [
 [<?= json_encode($series) ?>]
 ]
 }, {
 low: 0,
  showArea: true
  });
  </script>

regards

It Should look likes

        /*
         * SELECT DATE_FORMAT(created, '%Y-%m') as month, SUM(price_ht) as total 
         * FROM orders
         * GROUP BY DATE_FORMAT(created, '%Y-%m')
         */
        $sales = $this->Orders->find();
        $total = $sales->select([
            'month' => $sales->newExpr("DATE_FORMAT(created, '%Y-%m')"),
            'total' => $sales->func()->sum('price'),
            ])
            ->where(['user_id' => $this->authUser['id']])
            ->groupBy(['month'])
            ->toArray();

        $this->set('total', $total]);

thank you, i give a try, :bowing_man: :bowing_man: :bowing_man:

the view.ctp side,

i just add the js script and it show display out ?

   <div class="widget-content tab-content bg-white p-20">
            <div class="ct-chart tab-pane active" id="scoreLineToDay"></div>

        
            <script>
                new Chartist.Line('.ct-chart', {
                    labels: [<?= json_encode($months) ?>],
                    series: [
                        [<?= json_encode($amounts) ?>]
                    ]
                }, {
                    low: 0,
                    showArea: true
                });
            </script>


            <div class="ct-chart tab-pane" id="scoreLineToWeek"></div>
            <div class="ct-chart tab-pane" id="scoreLineToMonth"></div>

Hi, i tried to display the html using this method, but its not shown out, in view.ctp is there any thing i need to pay attention on?