Think about an app where you want to notify events to the users… probably you want to make it in realtime…
Web socket and Socket.IO in particular make it possible. But Laravel from it side doesn’t have direct support for http socket, so we have to implement a little NodeJS Socket.IO server and make possible to push message to it from the Laravel backend.
To make possible the communication from the two different backend servers, Laravel 5 and NodeJS we will use Redis. Redis is a key value storage with a publish/subscriber feature. Basically every message published on a specific queue will be intercepted from every subscriber, in this case the subscriber will be the NodeJS server.
Installing Redis
Redis installation is very easy. After downloadig the current stable release from it’s site unpack it and execute the script :
make
When the scripts ends you can start the server. For this tutorial we will leave all the setting as default so no other modification are needed.
src/redis-server
There is also a useful utility that can be started to verify connection and message pushed into the queue.
redis-cli monitor
The NodeJS server
The Node Express server is a basic implementation of a express application with Socket.io server in it. The big difference will be the inclusion of the Redis subscribe part. The server will be a subscriber of the ‘ message’ queue of Redis. When a new message is published on this queue the same message will be emitted to the socket server to all the connected clients.
In the Laravel root folder create a subfolder to host the NodeJS server. In the subfolder install via npm the following packages
npm install express redis socket.io --save
The code of the server will be in the server.js file
var app = require('express')(); var server = require('http').Server(app); var io = require('socket.io')(server); var redis = require('redis'); server.listen(8890); io.on('connection', function (socket) { console.log("new client connected"); var redisClient = redis.createClient(); redisClient.subscribe('message'); redisClient.on("message", function(channel, message) { console.log("mew message in queue "+ message + "channel"); socket.emit(channel, message); }); socket.on('disconnect', function() { redisClient.quit(); }); });
The code is self explanatory.
We started an http server ont the 8090 port and associated to it the Socket.IO server, then we created a Redis client and when a new socket client is connected we subscribe the message queue in Redis.
When something is pushed on the message queue a socket.emit is fired to each client.
To start the server, from the command line, move to the NodeJS folder ant type
node server.js
Laravel with Redis
In Laravel 5 the configuration to use Redis is already made, but you need some modification to use it, not described in the official documentation. First you need predis installed. You can download it via composer. Add the line below in the composer.json and update.
"require": { "laravel/framework": "5.0.*", "predis/predis": "~1.1@dev" },
composer update
To avoid conflict with Redis in PHP environment we will modify also the alias to the Redis module of Laravel. In the config app.php file change.
'Redis' => 'Illuminate\Support\Facades\Redis',
to
'LRedis' => 'Illuminate\Support\Facades\Redis',
Now all the modification is in place and we can start using Redis in Laravel without errors.
Laravel application
From the Laravel side we are going to implement a very basic application, just two pages, one to send message and one where we will receive this message in realtime without the need of reloads. All the logic will be in the sockeController actions.
php artisan make:controller socketController
In the controller 3 actions will be implemented. The first two will serve the form to insert new message and the other to publish the message on the Redis message queue. The index action will render a page where we start the Socket.IO client and update the DOM when a message income.
The code of the controller will be :
<?php namespace App\Http\Controllers; use App\Http\Requests; use App\Http\Controllers\Controller; use Request; use LRedis; class SocketController extends Controller { public function __construct() { $this->middleware('guest'); } public function index() { return view('socket'); } public function writemessage() { return view('writemessage'); } public function sendMessage(){ $redis = LRedis::connection(); $redis->publish('message', Request::input('message')); return redirect('writemessage'); } }
In the constructor the authentication system is set to guest to avoid login for every try. The index and writemessage are very simple method, just render a view. The important one is the sendMessage; in this method, we use Redis to publish the form input message to the queue and then redirect the application again to the form.
The form view is below, nothing expecial.
@extends('app') @section('content') <div class="container"> <div class="row"> <div class="col-md-10 col-md-offset-1"> <div class="panel panel-default"> <div class="panel-heading">Send message</div> <form action="sendmessage" method="POST"> <input type="text" name="message" > <input type="submit" value="send"> </form> </div> </div> </div> </div> @endsection
The page where the message will be received need some import and some javascript lines to make the socket working. We used a simple JQuery append to update the DOM but would be very interesting to use also AngularJS to update the interface. Probably in a next tutorial we will see how to make it. By now the source of the socket page.
@extends('app') @section('content') <script src="//code.jquery.com/jquery-1.11.2.min.js"></script> <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script> <script src="https://cdn.socket.io/socket.io-1.3.4.js"></script> <div class="container"> <div class="row"> <div class="col-lg-8 col-lg-offset-2" > <div id="messages" ></div> </div> </div> </div> <script> var socket = io.connect('http://localhost:8890'); socket.on('message', function (data) { $( "#messages" ).append( "<p>"+data+"</p>" ); }); </script> @endsection
Last thing needed to the Laravel application is the routing to our pages. In the routes.php file put this line and you are done.
Route::get('socket', 'SocketController@index'); Route::post('sendmessage', 'SocketController@sendMessage'); Route::get('writemessage', 'SocketController@writemessage');
We are done. To test the application you can start the Redis and NodeJS server. When all is up open 2 browsers, one pointing to the sendmessage and one or more pointing to the socket page.
Now if you submit a message using the for, this message will be propagated to all the opened client and pushed to the DOM via Jquery. This implementation of the Socket.IO in Laravel is very easy and robust but have some downside. The first one is you need two http ports, one for the PHP server and one for the node/socket server. The other is in the code logic. If you want to use more then one channel you have to modify the NodeJS server too and not only the Laravel Controller.
It was interesting to use Socket.IO in Laravel so probably i’ m going to study it better and write some more tutorial on the argument.
Be the first one to write a response :(
{{ reply.member.name }} - {{ reply.created_at_human_readable }}