l5

Greetings,

As of this writing, I am using dev branch of Laravel as 5.1 has yet to be released. This post’s may not be usable if there’s any improvements or changes made to the broadcasting feature.

Our great lord Taylor Otwell has shown us on how we can easily integrate real-time functionality with the new event broadcasting feature on L5.1, as soon as I saw his video on Laracasts, i immediately installed dev branch (5.1) of Laravel and started playing with it. You can try it yourself.
Note: This tutorial is for Redis driver which I find a little complicated to get it running than Pusher.

Using composer
composer create-project laravel/laravel L51 dev-develop
Warning! Since 5.1 is still undergoing final changes, highly recommended not to use it for production.

 

Installation

There are some few things we need to install first, kindly skip if your system already have the features below

1. Redis

http://redis.io/ and follow the instructions to download and install.

2. Node.js

https://nodejs.org/ and click install

The items below needed to be installed at your root directory of your Laravel 5.1 app. Navigate there to run the commands below

Navigate to your application’s root directory and type the following commands:

3. Socket.io  More info
npm install socket.io

4. Express
npm install express

5. ioredis  More info
npm install ioredis

6. Predis  More info
Required by Laravel to run Redis
composer require predis/predis

Create your Event

Now, its some 5.1 time. Navigate to your Laravel app root directory, run the command below
php artisan make:event MyEventNameHere

Okay after it says successful, head over to App/Events/MyEventNameHere

<?php namespace App\Events;

use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MyEventNameHere extends Event
{
    use SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should be broadcast on.
     *
     * @return array
     */
    public function broadcastOn()
    {
        return [];
    }
}

Now we implement the new ShouldBroadcast
class MyEventNameHere extends Event implements ShouldBroadcast

This will tell Laravel that this event should be broadcasted to client-side when it is fired.

Now how do we get data across, easy, as explained by Taylor Otwell in his Laracasts video, any public variables declared will be serialized and send over while private variables will not be serialized.

So now I have added a public variable and changed the broadcastOn method to return the channels I want this event to broadcast on. I will name it test-channel

class MyEventNameHere extends Event implements ShouldBroadcast
{
    use SerializesModels;

    public $data;
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->data = array(
            'power'=> '10'
        );
    }

    /**
     * Get the channels the event should be broadcast on.
     *
     * @return array
     */
    public function broadcastOn()
    {
        return ['test-channel'];
    }
}

Routes

We will be creating a route where by on load, it will fire the event, thus updating all of the client browsers with new data. In which my example above is to send a data with power 10.
Go to App/Http/routes.php

Add in

Route::get('test', function () {
    event(new App\Events\MyEventNameHere());
    return "event fired";
});

So, everytime we visit http://localhost/myapp/public/test , it will fire the event, thus broadcasting to all clients who are listening.

Coding NodeJS Socket.io Server

Now, we need to get a Socket.io server up so it can emit and listen for new messages.

Add this to your laravel 5.1 app root directory, name it as socket.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();

redis.subscribe('test-channel', function(err, count) {

});

redis.on('message', function(channel, message) {
   console.log('Message Recieved: ' + message);

    message = JSON.parse(message);

    io.emit(channel + ':' + message.event, message.data);

});

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

As you can see from the above code, we are requring all the modules we just installed above, and made a simple server on port 3000.

Start up Redis

Make sure you have installed Redis and predis properly. Now open up your console/terminal navigate to the your redis folder.

cd src
Then,
cd ./redis-server

You can now see Redis server is up and running

Optional: If you have brew you can install redis easily by running this command
brew install redis
Then, to start the server
redis-server

Config Broadcast Driver

Go back to your Laravel app, head to config/broadcasting.php, now change the driver to Redis

'default' => env('BROADCAST_DRIVER', 'redis'),

Start up Socket.io server

At your root directory of your Laravel app, run
node socket.js

You will see
Listening on Port 3000
If not, something must be wrong, double check your installations.

Socket.io Client Side

Okay we have just started server-side socket.io, how about client side?

We need to get socket.io.js script on our client side. I assume you have made a view.

Where’s Socket.io.js? Its in your
node_modules/socket.io/node_modules/socket.io-client/

Copy the socket.io.js to your public folder, place it inside assets/js(if you dont have the folder, make one)

View

Here’s what my view looks like, i have included jquery in my layout blade file : app.

@extends('app')

@section('content')
    <p id="power">0</p>
@stop

@section('scripts')

    <script src="{{ asset('assets/js/socket.io.js') }}"></script>

    <script>
    var socket = io('http://localhost:3000');
    socket.on("test-channel:App\\Events\\MyEventNameHere", function(message){
         // increase the power everytime we load test route
         $('#power').text(parseInt($('#power').text()) + parseInt(message.data.power));
     });
    </script>


@stop

As you can see I linked the socket.io.js and made a script to listen for the event broadcast, then increase the power counter.

That’s all, try opening up test route in a tab and your main view in another tab, keep on refreshing test route and see the power going up. My power is already over 9000.

Conclusion

This is a great feature to be added to the-already-amazing Laravel framework. Many people will love this.
This feature can be used to make real-time applications like chatbox and live notifications.

Why I didn’t chose pusher?
Its not really free if your user base is huge and theres slight http latency since the we still need to call up pusher service. So running redis locally side by side with the app is my favourite way.

Special thanks to Taylor Otwell for creating such a beautiful framework.

Lead developer of Nedex.io. From Malaysia.


  • Sores

    Hello. I followed your tutorial but no luck to get the final result. I installed all what is need, and started nodejs socket.js

    When i reload the page, i receive 3 GET request but with null result.

    GET http://l51.dev:8080/socket.io/?EIO=3&transport=polling&t=1430750374952-0
    GET http://l51.dev:8080/socket.io/?EIO=3&transport=polling&t=1430750375056-1&sid=KxbwFPuHWY3XMDZCAAAG
    GET http://l51.dev:8080/socket.io/?EIO=3&transport=polling&t=1430750375103-2&sid=KxbwFPuHWY3XMDZCAAAG

    Where i`m wrong?

    • Sores

      I forgot to tell you that in ubuntu terminal console i receive something like that:

      nodejs socket.js
      Listening on Port 8080
      Message Recieved: {“event”:”App\Events\Task”,”data”:{“data”:{“power”:”10″}}}

      • Hi there Sores,
        yea your socket.io server is alright. Receiving null is probably due to your client side code, double check your client side code.

        I think your’e using vagrant, so make sure you changed your localhost to l51.dev

        var socket = io(‘http://l51.dev:3000’);
        socket.on(“test-channel:App\Events\MyEventNameHere”, function(message){
        console.log(message); //for debug, see console of your browser
        // increase the power everytime we load test route
        $(‘#power’).text(parseInt($(‘#power’).text()) + parseInt(message.data.power));
        });

        • Vladimir Rakita

          I copied your code and got same error as Sores. I am using vagrant and homestead.

        • Kory Marks

          Overtime the localhost/event page is called the event is fired but the socket.on(“test-channel:App\Events\MyEventNameHere”, function(message){
          console.log(message); /// it keeps coming up null. So the code won’t add power correctly. Can you give any other help
          }

          • Zainoz Zaini

            At earlier I am having same null issue but solved after declare public $data; at the top,

        • Xroot

          you don’t have any payload object within your json , soon socket.js change : io.emit(channel + ‘:’ + message.event, message.payload); with io.emit(channel + ‘:’ + message.event, message.data);

      • Xroot

        change this line on socket.js : io.emit(channel + ‘:’ + message.event, message.payload); to io.emit(channel + ‘:’ + message.event, message.data);

    • Monish

      Did you find a solution to this problem? I am having the same issue.

      • Liman

        Hey, there.. I followed all the instruction.. But i got the problem with the client side, I got this error “ReferenceError: io is not defined” even though the serverside is working because
        node socket.js command receive this.

        C:xampphtdocsbroadcast>node socket.js
        Listening on Port 3000
        Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}
        Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}
        Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}

        This is my client app.blade.php

        Broadcaster

        0

        var socket = io(‘http://localhost:3000’);
        socket.on(“test-channel:App\Events\MyEventNameHere”, function(message){
        // increase the power everytime we load test route
        $(‘#power’).text(parseInt($(‘#power’).text()) + parseInt(message.data.power));
        });

  • Banda E Khuda

    I am newbie … Can you tell me where to place view? should I copy this code into app.blade.php in some other file?

    • You can create a view in ./resources/views/ and let’s say sample.blade.php. Now add in routes file to access that view.

      Sample:

      1.) app/Http/routes.php

      Route::get(‘default’, function() {
      return view(‘default’);
      });

      // You can access this on http://localhost:8000/default if you’re running default php artisan. Or use your hostname and append /default.

  • Anyone tried to test this on Chrome on your mobile? Got it working on desktop (Chrome, IE, FF) but not on mobile browsers. What could I probably be missing? Thanks

    • Hi,

      Can you tell me which URL you are accessing your laravel app on your mobile device?Are you testing locally or already on a server?

      • Thanks for the prompt response. I have tried it on http://webriqs.com/sample. You can use this credentials: u: revalderc@gmail.com | p: nick to get the page working. Now, the page that’ll trigger the event is on http://webriqs.com/test

        Btw, if it helps, I am running a Micro AWS instance and installed redis and node.js and followed all the exact steps here. Thanks. I’ll surely want to see your latest tutorial. I’m gonna follow you now, here’s my twitter @dorelljames

  • Hi guys, I will be writing a newer version of this tutorial with a real world implementation example. Stay tuned. You can follow me on twitter @elsodev for latest updates.

    • senty

      @elsodev:disqus can you please expand on private event broadcasting such as, ‘UserA wrote on your wall’, ‘UserC replied your post’.

  • KL-Developer

    hello elson,
    may i know what Queue Driver you’re using? Are you also using redis? (QUEUE_DRIVER=redis)

  • Liman

    Hey, there.. I followed all the instruction.. But i got the problem
    with the client side, I got this error “ReferenceError: io is not
    defined” even though the serverside is working because
    node socket.js command receive this.

    C:xampphtdocsbroadcast>node socket.js
    Listening on Port 3000
    Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}
    Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}
    Message Recieved: {“event”:”App\Events\MyEventNameHere”,”data”:{“data”:{“power”:”10″}}}

    This is my client app.blade.php

    Broadcaster

    0

    var socket = io(‘http://localhost:3000’);
    socket.on(“test-channel:App\Events\MyEventNameHere”, function(message){
    // increase the power everytime we load test route
    $(‘#power’).text(parseInt($(‘#power’).text()) + parseInt(message.data.power));
    });

  • Sazzad Tushar Khan

    Please change message.payload to message.data instead we, all newbies, are confused.
    Anyway thanks for the good article which helped me a lot to start

  • Martin
    • Hi Martin, actually that article is based off this article, you can see the author linked back to here at second paragraph.

      “You can view the original article where I got some of the information from;”

      • Martin

        My apologies. Thanks for the clarification!

    • check for yourself.

  • Ryan Kang

    Hi, is there any updates on this tutorial? I changed “return ‘event fired'” to return view(‘mytest’); in order to point it to the view. I started socket.js by node socket.js. I get the message saying listening on port 3000.

    I went to my url mydomain.com:3000/test. But I get message like this: Cannot GET /test. Obviously something went wrong. I exactly followed the instruction above. It seems that something have been missing. Could you help me with this missing puzzle?

    Thanks!!

  • buffallo

    Hi, I have similar setup but would like to broadcast to everyone EXCEPT sender. I have a calendar application which duplicates events when receives the message from socket

  • Viko Wijaya

    Any idea to insert and show the data from database ? your example only from html, i have no idea to show it from database

  • Felipe

    Hi guys, to work this example dont forget run the following command:
    $ php artisan queue:listen

    • i have configured broadcasting to use redis (in broadcasting.php & .env) but it stores broadcast message in logs, any hint ?

  • Alfredo Concha

    hi @elsodev:disqus ! thanks for the tutorial 😀 but… how do I send the information to a specific user? let’s say I have a notification bar and I have 10 users, every user have their own notification!! how can I send the notifications to the respective users? thanks! =)

  • huglester

    Hello,

    any news on the ‘real work example’ as you mentioned?

  • Quinnie “Quin” Quinn

    I’ve implemented a similar structure for a system I’ve been working on (L5.1), but instead of running redis locally, I use an AWS ElastiCache (Redis) Instance, also used for job queue processing, and ultimately, api data caching.

    I really like redis. Tricky to query and analyse, but quick and effective. I tried using a database driver for job queues, but kept running into locked database tables, and redis came to the rescue.

    I briefly touched on the pusher implementation, but it had minor delays, and since I’m passing serialised objects around through event broadcasting, data isn’t exactly small. I also didn’t like the idea of an external entity having access to my data.

    It’s been 16 days since my changes were published, and redis processing is running favourably low on system resources, monitoring four separate queues with multiple processes per queue on a supervisor configured artisan queue worker daemon… I’m in love with laravel.

    • Alex Happell

      Hi quinnie, I am interested to hear how you were able to implement Elasticache Redis with Laravel? Are there any tutorials/resources you can point me towards?

      Thanks!

      • Quinnie “Quin” Quinn

        Hi Alex,

        Honestly, the task was very much trial and error based. I started on the Laravel documentation on Event Broadcasting and Queuing background jobs. I first followed the pusher route and then redis, all according to L51 documentation, but that had me pull my hair out, more often than not.

        Anyway, once I had processing functional through a local redis server instance, i followed AWS docs and configured ElastiCache with two nodes, which gave me a remote endpoint to the redis instance. I configured a security group as instructed, and assigned it to my EC2 instance, and then used the redis-cli to establish a connection to ElastiCache from the command line of my EC2 server. As soon as I managed to successfully connect to ElastiCache, I updated my queue and broadcast drivers to point to the ElastiCache endpoint, and everything fell into place.

        During development I accessed hundreds of resources online, but I couldn’t find any resources detailing the steps to follow for my scenario. It was ultimately a combination of many resources combined that eventually gave me a functional flow for my process.

        I could go through my bookmarks and history to point you to all the resources I accessed, but 80% of those resources sent me into all sorts of places that just confused the matter.

        I’ll spend some time going through everything I found online, and compile a list of resources that were actually useful, and then I’ll have a go at writing a tutorial on the topic, that covers the entire process from start to finish.

        In the meantime, all I can really give you is:

        http://blog.nedex.io/laravel-5-1-broadcasting-events-using-redis-driver-socket-io/

        https://www.sitepoint.com/real-time-apps-laravel-5-1-event-broadcasting/

        https://laravel.com/docs/5.1/events

        And:

        http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/GettingStarted.html

        Hope that helps for now. :)

        • Alex Happell

          Thank you so much for such a detailed response Quinnie, I’ll be sure to look through those links that you mentioned. I currently have an elasticache memcached node setup which will suffice for now I think.

          Many thanks once again!

          • Quinnie “Quin” Quinn

            Yeah, that should be perfect. I never actually intended using ElastiCache to be honest. We also had an idle ElastiCache instance that was yet to be configured for memcache use. At the time I wasn’t aware that ElastiCache even had Redis. I just happened to stumble upon it, and I’m very glad I did. The process is running very smoothly, and to this day, is yet to fail. My redis monitoring dashboard indicates that more than 73 million commands have been processed through 67 thousand connections, and memory use has not exceeded 5Mb since uptime, currently sitting on 4.82M. How accurate those stats are, is unclear at this point, however, nonetheless…
            Mind = Blown :)

            Hope you manage :)

  • Joao Paulo Nóbrega

    Error while reading line from the server. [tcp://localhost:6379], when i change queue driver to regis, help

  • Victor

    excelente tutorial, thak you

  • More than a year old yet very helpful! Kudos! Thank you for this detailed article.

  • Michael Mendoza

    is it possible to production? what configuration do we need in order to run smoothly in production?

  • Ronel Aparri Deita

    Thanks!

  • Jeff Parr

    This is great with queue driver set to synch, but there is a problem, when I try to use Redis as queue driver. Simply nothing happens.

    • Quinnie “Quin” Quinn

      Do you have redis-server installed and running? Also make sure that your configuration is correct, for the redis port. I use redis as queue, cache and session drive running without any problems.

      • Jeff Parr

        Thank you for your answer.
        I must say … shame on me :)
        My queue:listen daemon got ‘exorcised’ (died), that is why redis queues were DOA.

    • Quinnie “Quin” Quinn

      Also, you can monitor redis processing with the redis-cli, which will output log data while running.