More

    Tableau de bord d’une application en temps réel avec Yii2, Node.js, MySQL et Chart.js

    Dans cet article, nous allons créer un tableau de bord capable d’afficher des graphiques à partir de données en temps réel. Les données que nous utilisons comme simulations sont la population d’une ville. Si vous mettez à jour vos données sur les résidents, que vous les ajoutez ou les supprimez, le graphique changera en temps réel sans qu’il soit nécessaire de rafraîchir la page.

    Avant de commencer, nous devons nous préparer :

    1. Webserver est installé, voir Comment configurer l’hôte virtuel XAMPP dans Windows 10
      .
    2. Yii2 est installé, voir Comment installer Yii2 Advanced via Composer
      .
    3. Node.js est déjà installé, voir Créer des applications en temps réel avec Nodes.js
      .
    4. Chart.js.

    Etapes pour créer un tableau de bord en temps réel avec Yii2, Node.js, MySQL et Chart.js

    A. Créer une table avec MySQL

    Créez des tables avec le nom « ville » et des colonnes avec les noms « id » et « population ». Il est également plus facile d’exécuter les scripts SQL suivants.

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

    B. Créer un serveur Node.js

    1. Mettre en place un serveur Node.js comme dans Créer des applications en temps réel avec Nodes.js.
    2. Dans le fichier « server.js », nous devons créer une « API » qui mettra à jour les données du graphique que nous avons créé avec Chart.js après que les données aient été stockées avec succès par Yii.
    3. Lorsque l’utilisateur ouvre la page du tableau de bord pour la première fois, nous vérifions si les données initiales pour le graphique du tableau de bord sont disponibles, sinon Yii enverra les données initiales.
    app.post('/status', (req, res) => {
        res.send(isInitData);
    });
    
    app.post('/initData', (req, res) => {
        if(!isInitData){
            myData = req.body;
            isInitData=true;
        }
        res.send('success');
    });
    1. Ensuite, nous allons créer une « API » qui mettra à jour les données sur les opérations de crud sur 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 complet du fichier 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. Configuration sur Yii2

    1. Créez une classe « myCurl.php » avec la fonction « CurlToNodejs », pour savoir comment créer une fonction vous pouvez consulter [Yii2] How to create and use functions in Yii2 Basic and Advanced Templates.
    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. Ensuite, nous créons une vue « myChart.php » pour afficher les graphiques du tableau de bord. Pour l’utilisation de chart.js, vous pouvez le voir sur 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>

    Dans « SiteController.php », nous ajoutons « actionMychart ». Dans cette fonction, on vérifie si les données initiales sont disponibles ou non. Si ce n’est pas le cas, une requête sera faite à la base de données pour obtenir les données initiales.

        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');
        }
    1. Jusqu’à cette étape, nous pouvons déjà afficher les graphiques du tableau de bord. Cependant, il n’a pas été possible d’afficher les changements de données. Cette fois-ci, nous allons utiliser « Gii » pour faire du CRUD. Pour plus de détails, vous pouvez consulter la page Générer du code avec Gii.
    2. Créer un modèle « City » avec un « Gii Generator Model ». De cette étape sera formé un fichier « /models/City.php ».
    3. Puis le faire avec « CRUD Generator Gii » à partir du modèle. A partir de cette étape, les fichiers suivants seront formés.
    nodejs yii2 mysql chartjs 01
    1. L’étape suivante consiste à ajouter un script à « CityController.php » qui notifiera à Node.js les changements de données en utilisant la fonction « myCurl » que nous avons créée plus tôt.
    2. Remplacer « actionCreate » par ceci
        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. Remplacez ensuite « actionUpdate » par ceci
        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. Ensuite, modifiez « actionDelete » comme suit
        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. Exécution d’une application

    1. Exécutez le serveur Node.js avec
    node server.js
    1. Si tous les processus sont corrects, c’est ce que vous verrez.
    nodejs yii2 mysql chartjs

    Dernières articles