Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mstnorris's avatar

A good resource for implementing a simple notification system in Laravel 5.1 and Socket.io

I'm using a Mac with Homestead and I also have a Digital Ocean server provisioned using Laravel Forge.

I'm just playing around at the moment but I was wondering if anyone has set up a basic implementation of a notification system using Laravel 5.1 and Socket.io. I appreciate that Laravel 5.1 hasn't been released yet but the process should be similar between that and Laravel 5 (v. 5.0.32).

I am building an app where user's submit timesheets and other data, it is then checked by their superiors and passed up the chain. I would like to know how I can send notifications when a new timesheet was added for example.

I have watched Taylor's episode on Broadcasting Events in Laravel 5.1 but he doesn't go into much detail about the node.js part nor the Redis configuration.

Any tutorials, sample code, and gotchas that I should look out for when using Forge for example, will be greatly appreciated.

Thanks in advance for your input.

0 likes
37 replies
pmall's avatar

Yes I would be interested too by broadcasting events using nodejs

mstnorris's avatar

@pmall and others, when looking at Pusher's pricing namely the Sandbox plan what is a connection?

It includes 20 max connections, 100k messages per day, SSL protection and unlimited channels.

I'm looking at Pusher as I'm thinking (I may be wrong) that it is easier to implement as they do most of the work.

toniperic's avatar

@mstnorris 20 max connection means there can be 20 users connected simultaneously to the socket server.

mstnorris's avatar

@toniperic that's what I thought it meant; which could be a problem although it is unlikely that 20 people will be online at the same time. Am I right in thinking that if one user has two browsers open then that counts as two connections also?

Are you aware of what happens if you're on the Sandbox plan and you go over the connection limit?

toniperic's avatar

@mstnorris, yes, that's right, it's counted as two connections.

If you're running a website that has lots of visitors, it could easily be the case that Sandbox plan is not sufficient.

What happens when you hit the max connection limit is that socket server (hosted by Pusher) just keeps rejecting new connections, but the 20 connections that are alive can still send and receive messages. If the same thing happens on a paid plan - well, you'll receive an email when you are close to the limits of your plan. You are allowed 2 days a month over the limits before they hard limit your plan.

mstnorris's avatar

@toniperic thanks for the info, that's really helpful. I doubt I'd hit 20 connections to begin with as it is only to be used internally within a small team and not everyone will be online at the same time, although I know what some people are like with keeping tabs open so that could cause issues.

Have you yourself set up anything with socket.io?

pmall's avatar

What about setting this up with node js ? It is just for a small team intranet app, i don't need pusher.

mstnorris's avatar

@pmall I'm probably being totally ignorant here but I'd need socket.io and nodejs right? And yes, I would prefer to do that but I personally do not have the knowledge. I am however good at following instructions and reading through an article to set it up but I have doubts whether or not it will be a fairly straightforward thing to set up both in Homestead (for development and testing) and with my Digital Ocean server (provisioned through Forge).

toniperic's avatar

@pmall @mstnorris yes I have used node js and socket.io, only locally though.

I was really sceptic I'd get it right as I am not all that good with Javascript (and especially server-side'ish Javascript), but it was really easy.

I have used the official chat application example. It took me an hour of my free time, but it was definitely worth it going through the page and reading everything, then trying out in my code editor. It's amazing that you can do so much with only a couple of lines of code once you understand what they do.

@mstnorris as for original post - the concept is literally the same for both chat app and notifications system.

mstnorris's avatar

Thank you both, I've looked at the chat app and it's a little daunting but I will give it my best shot. See you in an hour or two ;)

pmall's avatar

@toniperic yes but what driver do you use in app/broadcast.php when using socket io ?

toniperic's avatar

@mstnorris I had the same feeling it's too overwhelming. Trust me, after you give it a shot and code along with the tutorial, you'll be so grateful to yourself that you've done it.

1 like
mstnorris's avatar

@toniperic in the chat app documentation, it says to create an index.js file and then run node index.js. As I am using Homestead; (a) Will this be an issue? (b) Can I create an app.js file within the public folder? Or should it reside elsewhere?

pmall's avatar

@toniperic humpf, this is a lot of stuffs to install just to enable broadcasting :(

toniperic's avatar

@pmall sadly yes, but still think how revolutionary this is for PHP apps. Much easier to make real-time apps with PHP than it was months or years before. Lets face it, we would just use server-polling before :)

toniperic's avatar

@mstnorris it's got to be something with your Redis server. You sure the server was running when you tested it?

mstnorris's avatar

@toniperic I can't be sure no ;p I'm running it on a brand new Laravel 5.1 installation and I haven't changed any of the names fro the article just so that I know it is working first before I modify it.

MyEventNameHere.php

<?php namespace App\Events;

use App\Events\Event;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

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'];
    }
}

package.json

{
  "private": true,
  "devDependencies": {
    "gulp": "^3.8.8",
    "laravel-elixir": "*"
  },
  "dependencies": {
    "express": "^4.12.4",
    "ioredis": "^1.4.0",
    "redis": "^0.12.1",
    "socket.io": "^1.3.5"
  }
}

composer.json

"require": {
    "predis/predis": "^1.1@dev"
},

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.payload);
});
http.listen(3000, function(){
    console.log('Listening on Port 3000');
});

.env

BROADCAST_DRIVER=redis

test.blade.php

<script src="{{ asset('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>
mstnorris's avatar

Ok, so I have run redis-cli monitor yet I am still getting the same error. Do I need to do anything in any particular order?

I currently have two tabs open, both SSH'd into Homestead and the pwd is the root of my project (project name: fiveone-socket). In the first tab I ran redis-cli monitor and in the second I ran node socket.js.

mehany's avatar

Can you guys take a look at Socketo.me and share what you think about it. It looks pretty good!

toniperic's avatar
Level 30

@mstnorris no need to do it. If you're using Homestead (like I am), you can just run redis-server from wherever you want.

What might differ from the tutorial I've linked you to is the IP address of the server. In the view file you might have code like

var socket = io('http://localhost:3000');

The localhost part should be substituted with Homestead IP address, which by default is 192.168.10.10, so it should be

var socket = io('http://192.168.10.10:3000');

That should get rid of the "Cannot connect to the server" error. Hope I helped.

Also, if you're following the tutorial, I think in socket.js file you should substitute

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

with

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

Apparently the property name has been changed from payload to data (just tested it now from scratch).

mstnorris's avatar

@toniperic I ran redis-server and got the following

redis-server
[4112] 03 Jun 15:48:14.834 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
[4112] 03 Jun 15:48:14.835 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
[4112] 03 Jun 15:48:14.836 # Redis can't set maximum open files to 10032 because of OS error: Operation not permitted.
[4112] 03 Jun 15:48:14.836 # Current maximum open files is 1024. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
[4112] 03 Jun 15:48:14.837 # Creating Server TCP listening socket *:6379: bind: Address already in use

Is this an issue?

toniperic's avatar

@mstnorris it means the server hasn't started.

Run redis-server --port 3001 and it'll start. You'll have to open another terminal though. If you hit CTRL+C it'll kill the redis server.

mstnorris's avatar

@toniperic Just so we're on the same page:

Thank you for your continuous help :)

  • I have redis-server running on port 3001
  • node socket.js running on port 3001
  • I hit the URI /fire in one tab,
  • and in another the home route /test where I get the following error: (which I assume is a good thing as it is working!)
TypeError: null is not an object (evaluating 'message.data')

$('#power').text(parseInt($('#power').text()) + parseInt(message.data.power));

socket.js node index.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.payload);
});
http.listen(3000, function(){
    console.log('Listening on Port 3000');
});

test.blade.php responds to URI /test

<script src="{{ asset('js/socket.io.js') }}"></script>
<script>
    //var socket = io('http://localhost:3000');
    var socket = io('http://192.168.10.10: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>

routes.php

Route::get('/', function() {
    return "go to /fire";
});

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

Route::get('test', function () {
    return view('test');
});
toniperic's avatar

Read my previous answer, I've edited it just a couple of seconds before you've posted so you probably missed that. You have to change "message.payload" to "message.data" in your socket.js file (and re-run node socket.js). It's just that object property name has been changed within the ioredis library by its author, no big deal.

Let me know if that helped.

mstnorris's avatar

Yes I had missed it. You got it!

Thank you @toniperic and @pmall for all your help. I might put together a little thread with what I've done so far to help others.

Thanks again, I'm sure I'll be asking more questions later when I've played around a little more :D

toniperic's avatar

@mstnorris glad you sorted it out. Told you it'll be a walk in the park. Now you can create real-time apps. ;)

1 like
mstnorris's avatar

@toniperic just a quick question, when I first started the tutorial I ran npm install socket.io and then followed everything else. It didn't work however, so I found a previous tutorial that I had just looked at and it said to install npm install --save express@4.10.2 and then it worked. Was that an oversight in the tutorial you showed me?

Next

Please or to participate in this conversation.