Chat en la aplicación de Yii2 utilizando WebSocket

 1.-  Añadir en el composer.json:

"consik/yii2-websocket": "^1.0"

2.- Ejecutar el composer update en el cmd:

composer update --prefer-dist

WebSockets es una conexión bidereccional del navegador web  con el servidor. Una vez que la conexión de Websocket esta establecida se mantiene abierta hasta que el cliente o el servidor decide cerrarla. Con esta conexión abierta el cliente o el servidor puede enviar un mensaje en cualquier momento, esto hace que la programación web se vuelva enteramente conducida por eventos, no solo cuando el usuario la inicie.

Ratchet es una librería de PHP WebSocket  cuyos componentes pueden hacer que la aplicación soporte WebSockets en el lado del servidor.

Con este widget podemos utilizar la librería de Ratchet y hacer nuestro chat asi como graficos en tiempo real etc.

3.- Revisar la documentación:

https://github.com/consik/yii2-websocket

http://socketo.me/

4.- Vamos a crear una carpeta que le vamos a llamar daemons (siguiendo el ejemplo que el hace en la documentación), en este caso yo la voy a crear entro del backend y dentro vamos a crear el archivo de chat ChatServer.php :

<?php

namespace backend\daemons;


use consik\yii2websocket\events\WSClientEvent;

use consik\yii2websocket\WebSocketServer;

use Ratchet\ConnectionInterface;

use Yii;

class ChatServer extends WebSocketServer

{


    public function init()

    {

        parent::init();


        $this->on(self::EVENT_CLIENT_CONNECTED, function(WSClientEvent $e) {

            $e->client->name = null;

        });

    }



    protected function getCommand(ConnectionInterface $from, $msg)

    {

        $request = json_decode($msg, true);

        return !empty($request['action']) ? $request['action'] : parent::getCommand($from, $msg);

    }


    public function commandChat(ConnectionInterface $client, $msg  )

    {

        $request = json_decode($msg, true);

        $result = ['message' => ''];


        if (!$client->name) {

            $result['message'] = Yii::t('app', 'You need to be logged for chatting');

        } elseif (!empty($request['message']) && $message = trim($request['message']) ) {

            foreach ($this->clients as $chatClient) {

                $chatClient->send( json_encode([

                    'type' => 'chat',

                    'from' => $client->name,

                    'date' => date('Y-m-d H:i:s'),

                    'message' => $message

                ]) );

            }

        } else {

            $result['message'] =Yii::t('app', 'Enter a message');

        }


        $client->send( json_encode($result) );

    }


    public function commandSetName(ConnectionInterface $client, $msg)

    {

        $request = json_decode($msg, true);

        $result = ['message' =>Yii::t('app', 'User updated')];


        if (!empty($request['name']) && $name = trim($request['name'])) {

            $usernameFree = true;

            foreach ($this->clients as $chatClient) {

                if ($chatClient != $client && $chatClient->name == $name) {

                    $result['message'] = Yii::t('app', 'This user is logged in other computer and is chatting, you can´t use it');

                    $usernameFree = false;

                    break;

                }

            }


            if ($usernameFree) {

                $client->name = $name;

            }

        } else {

            $result['message'] = Yii::t('app', 'Invalid username');

        }


        $client->send( json_encode($result) );

    }


}


5.- De ahí vamos a ir a la carpeta de console/controllers y vamos a crear un archivo ServerController.php:

(La aplicación de console de Yii2 principalmente se usa para crear tareas de mantenimientos, esto nos ejecuta procesos desde el cmd, que desde el servidor con tareas programadas podemos ejecutar, en este caso la vamos a utilizar para que nos inicie la librería de ratchet que es la que permite el funcionamiento del websocket, básicamente que está allí escuchando hasta que ocurra algun evento, así lo entiendo yo)


<?php

namespace console\controllers;


use backend\daemons\ChatServer;

use consik\yii2websocket\WebSocketServer;

use yii\console\Controller;


class ServerController extends Controller

{

    public function actionStart($port = null)

    {

        $server = new ChatServer();

        if ($port) {

            $server->port = $port;

        }

        $server->start();

    }

}



5.1 Añadir en el main de console/config en components:


  'i18n' => [

            'translations' => [

               'app' => [

                    'class' => 'yii\i18n\PhpMessageSource',

                    'basePath' => '@common/messages',

                    'sourceLanguage' => 'en-US',

                ],

                'yii' => [

                    'class' => 'yii\i18n\PhpMessageSource',

                    'basePath' => '@common/messages',

                    'sourceLanguage' => 'en-US',

                ],

                'yii2mod.rbac' => [

                    'class' => 'yii\i18n\PhpMessageSource',

                    'basePath' => '@common/messages',

                    'sourceLanguage' => 'en-US',

                ],

                

            ],

        ],



6.- Vamos a la carpeta del proyecto y abrimos el cmd y ejecutamos:

Esto tenemos que programarlo en el servidor para que siempre se este ejecutando y asi la parte del servidor de  nuestro websocket se inicia

php yii server/start


7.- Vamos a crear una vista en backend/views/site chat.php:


<div class="card card-primary card-outline direct-chat direct-chat-primary">

    <div class="card-header">

    <h3 class="card-title"><?= Yii::t('app', 'Chat') ?></h3>


    <div class="card-tools">

      <button type="button" class="btn btn-tool" data-card-widget="collapse">

          <i class="fas fa-minus"></i>

      </button>

    </div>

    </div>

    <!-- /.card-header -->

    <div class="card-body">

    <!-- Conversations are loaded here -->

    <div class="direct-chat-messages" id="chat">

        <!-- /.direct-chat-msg -->

    </div>

      <!-- /.direct-chat-pane -->

    </div>

    <!-- /.card-body -->

    <div class="card-footer">

      <div class="input-group">

        <input type="text" id="message" name="message" placeholder="<?= Yii::t('app', 'Type Message ...') ?>" class="form-control">

        <span class="input-group-append">

          <button  id="btnSend" class="btn btn-primary"><?= Yii::t('app', 'Send') ?></button>

        </span>

      </div>

    </div>

    <!-- /.card-footer-->

</div>

<?php $this->registerJs('

    $(function() {

        var chat = new WebSocket("ws://localhost:8080");

        chat.onmessage = function(e) {

            var response = JSON.parse(e.data);

            if (response.type && response.type == "chat") {

                if(response.from == "'.Yii::$app->user->identity->username .'" ){

                      

                    $("#chat").append("<div class=\"direct-chat-msg\"><div class=\"direct-chat-infos clearfix\"><span class=\"direct-chat-name float-left\">"+response.from+" </span><span class=\"direct-chat-timestamp float-right\">"+response.date+"</span></div><i class=\"direct-chat-img fas fa-user-circle\" style=\"font-size:40px\"></i><div class=\"direct-chat-text\">"+response.message+"</div></div>");

                         

                }else{

                    $("#chat").append("<div class=\"direct-chat-msg right\"><div class=\"direct-chat-infos clearfix\"><span class=\"direct-chat-name float-right\">"+response.from+" </span><span class=\"direct-chat-timestamp float-left\">"+response.date+"</span></div><i class=\"direct-chat-img fas fa-user-circle\" style=\"font-size:40px\"></i><div class=\"direct-chat-text\">"+response.message+"</div></div>");

                }


            } else if (response.message) {

                console.log(response.message);

            }

        };

        chat.onopen = function(e) {

            console.log("Connection established! Please, set your username.");

            chat.send( JSON.stringify({"action" : "setName", "name" : "'. Yii::$app->user->identity->username .'"}) );

        };

        $("#btnSend").click(function() {

            if ($("#message").val()) {

                chat.send( JSON.stringify({"action" : "chat", "message" : $("#message").val()}) );

                $("#message").val("");

                console.log(chat);

            } else {

                alert("'.Yii::t('app', 'Enter the message').'");

            }

        });


           

       

        

        

    })

', \yii\web\View::POS_END); ?>


8.- Vamos a crear el actionChat en el SiteController.php:


public function actionChat()

{

    return $this->render('chat');

}


8.1.- Sustituir el behavior del site controller o añadir la actionchat


   public function behaviors()

    {

        return [

            'verbs' => [

                'class' => VerbFilter::className(),

                'actions' => [

                    'delete' => ['POST'],

                ],

            ],

        ];

    }


    public function behaviors()

    {

        return [

            'access' => [

                'class' => AccessControl::className(),

                'rules' => [

                    [

                        'actions' => ['login', 'error'],

                        'allow' => true,

                    ],

                    [

                        'actions' => ['logout', 'index','chat'],

                        'allow' => true,

                        'roles' => ['@'],

                    ],

                ],

            ],

            'verbs' => [

                'class' => VerbFilter::className(),

                'actions' => [

                    'logout' => ['post'],

                ],

            ],

        ];

    }


9.- Revisar en site/chat


10.- Abrir 2 ventanas del navegador y revisar con usuarios diferentes











Comentarios

  1. He visto todos tus videos y debo confesar que son excelentes todos. Eres muy organizada y domina este framework, que para mí es uno de los mejores, con un talento especial. He visto muchos videos de yii2 pero ninguno se compara con estos. Gracias por compartir tus conocimientos y espero nos siga brindando explicaciones con ese maravilloso talento. Felicitaciones.

    ResponderEliminar
  2. Muchas gracias por tu comentario, espero poder hacer más videos y que te sigan pareciendo igual de buenos.

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

AdminLTE3 integración Yii2

RBAC Yii2 utilizando la extensión "yii2mod/yii2-rbac": "*"

Instalación de Yii2 (Windows)