En este artículo crearemos un cuadro de mandos capaz de mostrar gráficos a partir de datos en tiempo real. Los datos que utilizamos como simulación son la población de una ciudad. Si actualizamos los datos de los residentes, los añadimos o eliminamos, el gráfico cambiará en tiempo real sin necesidad de refrescar desde la página.
Antes de empezar, tenemos que prepararnos:
- Webserver está instalado, consulte Cómo configurar el host virtual XAMPP en Windows 10
. - Yii2 está instalado, véase Cómo instalar Yii2 Advanced a través de Composer
. - Node.js ya está instalado, consulte Crear aplicaciones en tiempo real con Nodes.js
. - Chart.js.
Pasos para Crear un Dashboard de Aplicación en Tiempo Real con Yii2, Node.js, MySQL y Chart.js
A. Crear una tabla con MySQL
Cree tablas con el nombre «ciudad» y columnas con los nombres «id» y «población». O es más fácil ejecutar los siguientes scripts sql.
CREATE TABLE 'city' ( 'id' CHAR(16) NOT NULL PRIMARY KEY, 'population' INT(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
B. Crear un servidor Node.js
- Configurar un servidor Node.js como en Crear aplicaciones en tiempo real con Nodes.js.
- En el archivo «server.js», lo que necesitamos crear es una «API» que actualizará los datos en el gráfico que creamos con el Chart.js después de que los datos sean almacenados con éxito por Yii.
- Cuando el usuario abre por primera vez la página del cuadro de mando, comprobamos si los datos iniciales para el gráfico del cuadro de mando están disponibles, si no es así Yii enviará los datos iniciales.
app.post('/status', (req, res) => { res.send(isInitData); }); app.post('/initData', (req, res) => { if(!isInitData){ myData = req.body; isInitData=true; } res.send('success'); });
- A continuación vamos a crear una «API» que actualizará los datos sobre las operaciones crud en 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'); });
- Script completo del archivo 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("issuer 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("initial data issuer"); socket.emit('initialData', myData); } });
C. Configuración en Yii2
- Crea una clase «myCurl.php» con la función «CurlToNodejs», para saber cómo crear una función puedes ver en [Yii2] Cómo crear y usar Funciones en Plantillas Básicas y Avanzadas de Yii2.
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; } }
- Después creamos una vista «myChart.php» para mostrar los gráficos desde el dashboard. Para usar chart.js puedes verlo en www.chartjs.org.
<?php /* @var $this yiiwebView */ $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] = [i] (.id data); values [i] = [i] (.population data); } 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' => yiiwebView::POS_HEAD] $this->registerJsFile('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js', ['position' => yiiwebView::POS_HEAD] ); ?><div class="site-index"> <div class="body-content"> <div id="container" style="width: 75%;"> <canvas id="myChart"></canvas> </div> </div> </div>
Mientras que en «SiteController.php» añadimos «actionMychart». En esta función, comprueba si los datos iniciales están disponibles o no. De lo contrario, se hará una consulta a la base de datos como los datos iniciales.
public function actionMychart() { $response = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/status'); if ($response === 'false') { $data = commonmodelsCity::find() ->asArray() ->all(); $response 1 = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/initdata', json_encode($data)); } return $this->render('myChart'); }
- Hasta este paso, ya podemos mostrar los gráficos del cuadro de mandos. Sin embargo, no ha sido capaz de mostrar los cambios de datos. En esta ocasión utilizaremos «Gii» para realizar CRUD. Para más detalles, puedes ver el Generando código con Gii.
- Crear un modelo de «Ciudad» con un «Modelo Generador Gii». A partir de este paso se formará un archivo «/models/City.php».
- A continuación, hacer con «CRUD Generador Gii» del modelo. A partir de esta etapa, se formarán los siguientes archivos.
- El siguiente paso es añadir un script a «CityController.php» que notificará a Node.js los cambios de datos utilizando la función «myCurl» que creamos anteriormente.
- Cambia «actionCreate» por esto
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, ]); }
- Then change «actionUpdate» to this
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, ]); }
- Y luego cambia «actionDelete» por algo como esto
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'] }
Otros artículos interesantes
D. Ejecutar una aplicación
- Ejecuta el servidor Node.js con
node server.js
- Si todos los procesos son correctos, lo verás así.