What are we creating ?

Laravel Installation and Configuration

Install a fresh copy of laravel and configure your database . I am using mysql as my database and redis to publish/subscribe events .

Now lets create a listener which listens to our update user event . Create a new folder inside the app and name it KodeInfo , create one more folder inside app/KodeInfo and name it Handlers

Add this to autoload classmap as below and run php artisan dump-autoload

"app/KodeInfo", "app/KodeInfo/Handlers"

php artisan dump-autoload

Now create a new class inside our app/KodeInfo and name it UserUpdatedEventHandler

<?php namespace KodeInfo\Handlers; use Redis; use Response; class UserUpdatedEventHandler { CONST EVENT = 'users.update'; CONST CHANNEL = 'users.update'; public function handle($data) { $redis = Redis::connection(); $redis->publish(self::CHANNEL, $data); } }

We will create a listeners.php in app folder and will listen for event users.update . whenever users.update it will execute handle method of UserUpdatedEventHandler class which will publish our data to users.update channel . So that means we have to listen for our event users.update in our angularjs code and act accordingly .

listeners.php



<?php Event::listen(\KodeInfo\Handlers\UserUpdatedEventHandler::EVENT, '\KodeInfo\Handlers\UserUpdatedEventHandler');

Our UsersController will handle request from angularjs

<?php class UsersController extends BaseController { public function index(){ return View::make('index',['rows'=>User::all(),'window'=>new \KodeInfo\JSHelper]); } public function addUser(){ $user=new User(); $user->name = Input::get('name'); $user->email = Input::get('email'); $user->save(); Event::fire(\KodeInfo\Handlers\UserUpdatedEventHandler::EVENT, array(User::all())); } public function updateUser(){ $user=User::find(Input::get('id')); $user->name = Input::get('name'); $user->email = Input::get('email'); $user->save(); Event::fire(\KodeInfo\Handlers\UserUpdatedEventHandler::EVENT, array(User::all())); } public function deleteUser($user_id){ User::find($user_id)->delete(); Event::fire(\KodeInfo\Handlers\UserUpdatedEventHandler::EVENT, array(User::all())); } public function all(){ return Response::json(User::all()); } }

We are using same view files which we have used in our previous tutorial Laravel Admin Panel . So we are using Adminlte with following directory structure

I wont be putting all views here so please have a look at views on github . We will get back to our app and work on nodejs,redis,angularjs . Below is our index.blade.php

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Laravel Realtime App</title> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'> {{HTML::style("/css/bootstrap.min.css")}} {{HTML::style("/css/font-awesome.min.css")}} {{HTML::style("/css/ionicons.min.css")}} {{HTML::style("/css/AdminLTE.css")}} <!--[if lt IE 9]> {{HTML::script("https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js")}} {{HTML::style("https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js")}} <![endif]--> <script> window.extras = window.extras || {{$window}}; </script> @yield('styles') <base href="/"/> </head> <body class="skin-blue" ng-app="DemoApp"> <!-- header logo: style can be found in header.less --> @include('layouts.header') <div class="wrapper row-offcanvas row-offcanvas-left"> <!-- Left side column. contains the logo and sidebar --> @include('layouts.navigation') <!-- Right side column. Contains the navbar and content of the page --> <aside class="right-side"> <div class="col-md-12"> <div ng-view></div> </div> </aside> <!-- /.right-side --> </div> <!-- ./wrapper --> <!--Template Plugins--> {{HTML::script("/js/jquery.2.0.3.js")}} {{HTML::script("/js/jquery-ui-1.10.3.min.js")}} {{HTML::script("/js/bootstrap.min.js")}} {{HTML::script("js/plugins/iCheck/icheck.min.js")}} {{HTML::script("js/AdminLTE/app.js")}} <!--AngularJS--> {{HTML::script("https://code.angularjs.org/1.2.13/angular.js")}} {{HTML::script("//ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-route.js")}} {{HTML::script("//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js")}} {{HTML::script("//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js")}} <!--Socket.io--> {{HTML::script("http://localhost:3000/socket.io/socket.io.js")}} {{HTML::script("/angular/modules/angular-socket-io/socket.js")}} {{HTML::script("/angular/app.js")}} <!--Controllers and Services--> {{HTML::script("/angular/services/users-service.js")}} @yield('scripts') </body> </html>

In the above code, we are getting some variables to angularjs so that it will be helpful . We can send csrf_token with each post request to be safe from csrf attach and so on . We are using KodeInfo/JSHelper to do so

<script> window.extras = window.extras || {{$window}}; </script>

We have defined a ng-view in which our list will load and have some angular scripts . Here the main part in below which we will get back soon after covering nodejs . I have seen many people get strucked in this step of how to load socket.io.js

{{HTML::script("http://localhost:3000/socket.io/socket.io.js")}}

We have also using https://github.com/btford/angular-socket-io library to easily use socket.io inside angularjs .

Setting up Redis Server and NodeJS

I was using windows at the time of writing this post so i have downloaded win64 executable from this link . It is also included with the source code .

Now download and install nodejs from nodejs website and windows users make sure you have set the path for nodejs installation folder [mine was C:\Program Files

odejs] . Now start command prompt/terminal and navigate to your laravel project/public directory , create a new folder nodejs and navigate to nodejs from cmd/terminal , now lets install our dependencies using below command .

npm install socket.io express redis

Now create a new file inside public/nodejs and name it server.js

var express = require('express'), http = require('http'), server = http.createServer(app); var app = express(); const redis = require('redis'); const io = require('socket.io'); const client = redis.createClient(); server.listen(3000, 'localhost'); console.log("Listening....."); io.listen(server).on('connection', function(client) { const redisClient = redis.createClient(); redisClient.subscribe('users.update'); console.log("Redis server running....."); redisClient.on("message", function(channel, message) { console.log(message); client.emit(channel, message); }); client.on('disconnect', function() { redisClient.quit(); }); });

In the above code our nodejs is listening on port 3000 .

we have created a new redis client

const redisClient = redis.createClient();

and subscribed to users.update event

redisClient.subscribe('users.update'); console.log("Redis server running....."); redisClient.on("message", function(channel, message) { console.log(message); client.emit(channel, message); });

Once the event is fired we will send message to all subscribers to that channel .

Now go back to our index.blade.php do you remember what i told about socket.io script .

make sure the port which are we are using in server.js is same here .

Wrapping up with AngularJS

Our angularjs directory structure is below

In our app.js i have defined one route so you can expand it and do not have to declare routeprovider.

app.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/', { templateUrl: '/partials/users/index.html', controller: 'UsersController' }). otherwise({ redirectTo: '/' }); } ]);

We have defined socket factory

app.factory('socket', function ($rootScope) { var socket = io.connect('http://127.0.0.1:3000/'); return { on: function (eventName, callback) { socket.on(eventName, function () { var args = arguments; $rootScope.$apply(function () { callback.apply(socket, args); }); }); }, emit: function (eventName, data, callback) { socket.emit(eventName, data, function () { var args = arguments; $rootScope.$apply(function () { if (callback) { callback.apply(socket, args); } }); }) } }; });

Our userscontroller is basic it will load all users at startup and have methods to create , update or delete the user . In our userscontroller, we have listening for users.update event and get the new users set .

Final Step

Our final step is to run our redis server with admin rights , run our server.js using node which can be done like below in terminal / cmd

node server.js

I have also created a migration make sure to run

php artisan migrate

You can also monitor redis request using the redis-cli monitor

Now navigate to / route and you will see all users

Output:



Thanks

KodeInfo