Laravel 4 Real Time Chat

Wiki

Laravel is a free, open source PHP web application framework, designed for the development of MVC web applications. Laravel is released under the MIT license, with its source code hosted on GitHub. It’s beautifully written, full of features and the community is presently exploding. In this post, we will use it to create a socket based, real time chat application.

BrainSocket

BrainSocket is a Laravel package that allows you to get up and running with real-time event-driven PHP apps using WebSockets.

BrainSocket provides an Artisan command to setup and run a WebSocket server with Ratchet inside of a Laravel app.

Official Website brainsocket.brainboxmedia.ca

ReactPHP

Before we can understand Ratchet, we need to understand ReactPHP. ReactPHP was born out of the need to develop event-based, asynchronous PHP applications. If you’ve worked with Node.JS you’ll feel right at home developing applications with ReactPHP; as they share a similar approaches to code. We’re not going to develop our chat application in ReactPHP, but it’s a dependency for Ratchet ...

We can learn more about ReactPHP at: reactphp.org.

Ratchet

One of the many ways in which real-time client-server applications are made possible is by what’s called socket programming. Believe it or not; most of what you do on the internet depends on socket programming. From simple browsing to streaming — your computer opens a socket connection to a server and the server sends data back through it.

PHP supports this type of programming but PHP websites have not typically been developed with this kind of model in mind. PHP developers have preferred the typical request/response model, and it’s comparatively easier than low-level socket programming.

Enter ReactPHP. One of the requirements for building a fully-capable socket programming framework is creating what’s called an Event Loop. ReactPHP has this and Ratchet uses it, along with the Publish/Subscribe model to accept and maintain open socket connections.

ReactPHP wraps the low-level PHP functions into a nice socket programming API and Ratchet wraps that API into another API that's even easier to use.

We can learn more about Ratchet at: socketo.me.

Install Laravel through Composer. Edit your Laravel project's composer.json file and add the require brainboxlabs/brain-socket:

"require": {
    ...
    "cboden/ratchet"             : "0.3.*",
    "brainboxlabs/brain-socket"  : "dev-master"
},

Once the package and all of its dependencies have been installed we need to add the BrainSocketServiceProvider to our app/config/app.php file.

Add this line:

'providers' => array(
    ...
    'BrainSocket\BrainSocketServiceProvider',

to the end of the providers array in the config file.

There is also an optional but recommended Facade you should add to the aliases array in the app/config/app.php file.

'aliases' => array(
    ...
    'BrainSocket'     => 'BrainSocket\BrainSocketFacade',

Next open terminal and cd into your Laravel project directory.

run php artisan list and confirm you see the brainsocket: command in the list of commands. It should look like this:

Available commands:
brainsocket
    brainsocket:start

Once you have confirmed the list, run the following command to start the WebSocket server:

$ php artisan brainsocket:start

Note: The websocket server runs on port 8080 by default. You can change this with the optional --port=port_number on the end of the artisan command.

$ php artisan brainsocket:start --port=8081

At this point you should see a message in the terminal saying the websocket has been started on the selected port. Terminal will be locked down / unusable at this point, to stop the WebSocket server hit Ctrl C in the terminal.

Note: Any changes to your laravel app / code while the ws server is running are not taken into account. You need to restart the ws server to see any of your changes.

Lets stop the ws server now by hit Ctrl C in the terminal.

Next in your app/ folder create a file called events.php

Lets add the following code to events.php:

<?php

Event::listen('generic.event',function($client_data) {
    return BrainSocket::message('generic.event',array('message'=>'A message from a generic event fired in Laravel!'));
});

Event::listen('app.success',function($client_data) {
    return BrainSocket::success(array('There was a Laravel App Success Event!'));
});

Event::listen('app.error',function($client_data) {
    return BrainSocket::error(array('There was a Laravel App Error!'));
});

Now in app/start/global.php add the following line at the end of the file:

require app_path().'/filters.php';
require app_path().'/events.php';

Great! Now we have a few events to test out on the client side. Run the

$ artisan command php artisan brainsocket:start

to start the ws server again.

To make things easier we have created a simple js helper that allows us to interact with our new ws server a bit easier. It's not required but it handles some minor formatting tasks in the background so you don't have to and pairs nicely with our BrainSocket Facade.

Head over to github.com/BrainBoxLabs/brain-socket-js to grab it.

Load the script into your app:

<script type="text/javascript" src="js/brain-socket.min.js" />
Create the BrainSocket object:

window.app = {};

app.BrainSocket = new BrainSocket(
        new WebSocket('ws://localhost:8080'),
        new BrainSocketPubSub()
);

You can check out simple chat app in the example/ directory.

View

<div class="messenger bg-white">
    <div class="chat-header text-white bg-gray-dark">
        Real-time Chat
        <a href="#" id="chat-toggle" class="pull-right chat-toggle">
            <span class="glyphicon glyphicon-chevron-down"></span>
        </a>
    </div>
    <div class="messenger-body open">
        <ul class="chat-messages" id="chat-log">

        </ul>
        <div class="chat-footer">
            <div class="p-lr-10">
                <input type="text" id="chat-message"
                    class="input-light input-large brad chat-search" placeholder="Your message...">
            </div>
        </div>
    </div>
</div>

<script>
    $(function(){

        // var fake_user_id = Math.floor((Math.random()*1000)+1);
        var fake_user_id = {{ Auth::user()->id }};
        //make sure to update the port number if your ws server is running on a different one.
        window.app = {};

        app.BrainSocket = new BrainSocket(
                new WebSocket('ws://192.168.1.104:8080'),
                new BrainSocketPubSub()
        );

        app.BrainSocket.Event.listen('generic.event',function(msg){
            console.log(msg);
            if(msg.client.data.user_id == fake_user_id){
                $('#chat-log').append('<li><img src="{{ Auth::user()->portrait_small }}" class="img-circle" width="26"><div class="message">'+msg.client.data.message+'</div></li>');
            }else{
                var str_test='<li class="right"><img src="'+msg.client.data.user_portrait+'" class="img-circle" width="26"><div class="message">'+msg.client.data.message+'</div></li>';
                $('#chat-log').append(str_test);
            }
        });

        app.BrainSocket.Event.listen('app.success',function(data){
            console.log('An app success message was sent from the ws server!');
            console.log(data);
        });

        app.BrainSocket.Event.listen('app.error',function(data){
            console.log('An app error message was sent from the ws server!');
            console.log(data);
        });

        $('#chat-message').keypress(function(event) {

            if(event.keyCode == 13){

                app.BrainSocket.message('generic.event',
                        {
                            'message':$(this).val(),
                            'user_id':fake_user_id,
                            'user_portrait':'{{ Auth::user()->portrait_small}}'
                        }
                );
                $(this).val('');

            }

            return event.keyCode != 13; }
        );
    });
</script>

Laravel 4 Real Time Chat

Laravel 4 Real Time Chat
4 votes, 4.50 avg. rating (90% score)