Membuat Dashboard Aplikasi Real Time dengan Yii2, Node.js, MySQL dan Chart.js

Dalam artikel ini kita akan membuat sebuah dashboard yang bisa menampilkan grafik dari data secara real time. Data yang kita gunakan sebagai simulasi adalah populasi penduduk suatu kota. Jika kita melakukan update data penduduk, menambahkan atau menghapus, tampilan grafik akan berubah secara real time tanpa perlu melakukan refresh dari halaman.

Sebelum kita memulai, kita perlu mempersiapkan:

  1. Webserver sudah terpasang, lihat Cara Konfigurasi Virtual Host XAMPP di Windows 10
  2. Yii2 sudah terpasang, lihat Cara Install Yii2 Advanced via Composer
  3. Node.js sudah terpasang, lihat Membuat aplikasi real time dengan Node.js
  4. Chart.js.

Langkah-Langkah Membuat Dashboard Aplikasi Real Time dengan Yii2, Node.js, MySQL dan Chart.js

A. Membuat tabel dengan MySQL

Buat tabel dengan nama “city”, dan kolom dengan nama “id” dan “population”. Atau lebih mudahnya anda dapat menjalankan script sql berikut ini

CREATE TABLE `city` (
  `id` CHAR(16) NOT NULL PRIMARY KEY,
  `population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

B. Membuat server Node.js

  1. Siapkan server Node.js seperti pada Membuat aplikasi real time dengan Node.js.
  2. Pada file “server.js”, yang perlu kita buat adalah “API” yang akan melakukan update data pada grafik yang kita buat dengan Chart.js setelah data berhasil di simpan oleh Yii.
  3. Ketika user pertama kali membuka halaman dashboard, kita lakukan pengecekan apakah data awal untuk grafik dasboard sudah tersedia, jika belum Yii akan mengirimkan data awal tersebut.
app.post('/status', (req, res) => {
    res.send(isInitData);
});

app.post('/initData', (req, res) => {
    if(!isInitData){
        myData = req.body;
        isInitData=true;
    }
    res.send('success');
});
  1. Selanjutnya kita akan membuat “API” yang akan melakukan update data pada operasi CRUD pada Yii.
app.post('/newData', (req, res) => {
    switch (req.body.actions){
        case "create":
            myData.push({id: req.body.id, population: req.body. population});
            break;
        case "update":
            let i = myData.findIndex(label => label.id === req.body.id);
            myData[i]={id: req.body.id, population: req.body. population};
            break;
        case "delete":
            let l = myData.findIndex(label => label.id === req.body.id);
            myData.splice(l,1);
            break;
    }
    io.emit('newData', {id: req.body.id, population: req.body. population, actions:req.body.actions});
    res.send('success');
});
  1. Script lengkap dari file server.js
var app = require("express")();
var bodyParser = require('body-parser')
var http = require('http').Server(app);
var io = require("socket.io")(http,{cors: {origin:"*"}});

var myData = [];
var isInitData=false;

http.listen(3000, function () {
    console.log("Listening on 3000");
});

app.use(bodyParser.json({type: 'application/json' }));

app.post('/status', (req, res) => {
    res.send(isInitData);
});

app.post('/initData', (req, res) => {
    if(!isInitData){
        myData = req.body;
        isInitData=true;
    }
    res.send('success');
});

app.post('/newData', (req, res) => {
    switch (req.body.actions){
        case "create":
            myData.push({id: req.body.id, population: req.body. population});
            break;
        case "update":
            let i = myData.findIndex(label => label.id === req.body.id);
            myData[i]={id: req.body.id, population: req.body. population};
            break;
        case "delete":
            let l = myData.findIndex(label => label.id === req.body.id);
            myData.splice(l,1);
            break;
    }
    io.emit('newData', {id: req.body.id, population: req.body. population, actions:req.body.actions});
    console.log("emit new data "+req.body.id+" :"+req.body.actions);
    res.send('success');
});

io.on("connection", (socket) => {
    console.log("A user is connected");
    if(isInitData){
        console.log("emit initial data");
        socket.emit('initialData', myData);
    }
});

C. Konfigurasi pada Yii2

  1. Membuat class “myCurl.php” dengan fungsi “CurlToNodejs”, untuk cara membuat fungsi bisa Anda lihat pada [Yii2] Cara membuat dan menggunakan Fungsi pada Yii2 Basic dan Advanced Template
class myCurl extends Component
{
    public function CurlToNodejs($url,$postdata=null)
    {
        $header = ['Content-type: application/json'];
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
        $response = curl_exec($curl);
        return $response;
    }
}
  1. Setelah itu, kita membuat view “myChart.php” untuk menampilkan grafik dari dashboard. Untuk penggunaan Chart.js bisa anda lihat pada www.chartjs.org
<?php
/* @var $this yii\web\View */
$this->title = 'My Chart Application';
$script = <<< JS
	$(document).ready(function(){
	//Chart.js Configuration
	    const data = {
            datasets: [{
                label: 'My First Dataset',
                borderWidth: 1
            }]
        };
	    
	    const ctx = document.getElementById('myChart');
	    const myChart = new Chart(ctx, {
	        type: 'bar',
	        data: data,  
	    });	    
	   
	   function UpdateChart(chart, label, data) {
            chart.data.labels=label;
            chart.data.datasets.forEach((dataset) => {
                dataset.data=data;
            });
            chart.update();
       }
	   
       //Socket.io Configuration
	   const socket = io.connect( 'http://localhost:3000');
       var labels=[];
       var values=[];
       socket.on('initialData', function(data){
           for (let i = 0; i < data.length; i++){
               labels[i] = (data[i].id);
               values[i] = (data[i].population);
           }
           UpdateChart(myChart,labels,values);
       });
        socket.on('newData', function(data){
            switch (data.actions){
                case "create":
                    const i = labels.length;
                    labels[i] = data.id;
                    values[i] = data.population;    
                    break;
                case "update":
                    const l = labels.findIndex(label=>label===data.id);
                    values[l] = data.population;
                    break;
                case "delete":
                    const x = labels.findIndex(label=>label===data.id);
                    if (x > -1) {
                        labels.splice(x, 1);
                        values.splice(x, 1);
                    }
                    break;                   
            }
            UpdateChart(myChart,labels,values);
        });
     
    });
JS;
$this->registerJs($script);
$this->registerJsFile("https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js", ['position' => \yii\web\View::POS_HEAD]);
$this->registerJsFile('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js', ['position' => \yii\web\View::POS_HEAD]);
?>
<div class="site-index">
    <div class="body-content">
        <div id="container" style="width: 75%;">
            <canvas id="myChart"></canvas>
        </div>
    </div>
</div>

Sedangkan pada “SiteController.php” kita tambahkan “actionMychart”. Pada fungsi ini dilakukan pengecekan apakah data awal tersedia atau tidak. Jika tidak akan dilakukan query ke database sebagai data awal.

    public function actionMychart()
    {
        $response = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/status');
        if ($response === 'false') {
            $data = \common\models\City::find()
                ->asArray()
                ->all();
            $response1 = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/initdata', json_encode($data));
        }
        return $this->render('myChart');
    }
  1. Sampai pada langkah ini, kita sudah bisa menampilkan grafik dashboard. Akan tetapi belum bisa menampilkan perubahan data. Kali ini kita akan menggunakan “Gii” untuk membuat CRUD. Untuk lebih jelasnya bisa anda lihat pada Generating Code with Gii
  2. Buat model “City” dengan “Model Generator Gii”. Dari langkah ini akan terbentuk file “/models/City.php”.
  3. Kemudian buat dengan “CRUD Generator Gii” dari model tersebut. Dari tahap ini ini akan terbentuk file sebagai berikut
TOP TUTORIALS:  [yii2] Cara mudah encrypt / decrypt parameter URL
  1. Langkah selanjutnya adalah kita menambahkan script pada “CityController.php” yang akan memberitahu Node.js akan perubahan data dengan menggunakan fungsi “myCurl” yang kita buat sebelumnya.
  2. Ubah “actionCreate” menjadi seperti ini
    public function actionCreate()
    {
        $model = new City();
        if ($this->request->isPost) {
            if ($model->load($this->request->post()) && $model->save()) {
                $post=Yii::$app->request->post('City');
                $data=["id" => $post['id'], "population" => $post['population'],"actions"=>"create"];
                Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
                return $this->redirect(['view', 'id' => $model->id]);
            }
        } else {
            $model->loadDefaultValues();
        }
        return $this->render('create', [
            'model' => $model,
        ]);
    }
  1. Kemudian ubah “actionUpdate” menjadi seperti ini
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);
        if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
            $post=Yii::$app->request->post('City');
            $data=["id" => $post['id'], "population" => $post['population'],"actions"=>"update"];
            Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('update', [
            'model' => $model,
        ]);
    }
  1. Dan selanjutnya ubah “actionDelete” menjadi seperti ini
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();
        $data=["id" => $id, "population" =>"","actions"=>"delete"];
        Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
        return $this->redirect(['index']);
    }

D. Menjalankan aplikasi

  1. Jalankan server Node.js dengan
node server.js
  1. Jika semua proses sudah benar, Anda akan melihat seperti ini.

Tinggalkan Komentar

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *