Kerimg's avatar

Using Laravel with Ratchet to create real time applications without 3rd party services

Just joined Laracast recently and got to say that these are some high quality tutorials.

I was wondering if Laravel will ever be able to handle real time applications without a third party service like Pusher. Is it possible to combine Laravel and Ratchet (the PHP Websocket library) or to use Ratchet as a broadcasting service? Considering the growth and impact of real time applications, I think it'd be great to cover that topic in detail.

Thank you.

0 likes
9 replies
pmall's avatar

I was wondering if Laravel will ever be able to handle real time applications without a third party service like Pusher.

Of course it can, just use redis as a broadcasting queue and listen to it with socketio.

jimmck's avatar
jimmck
Best Answer
Level 13

Ratchet and ZMQ work great together. You can easily combine Vue or JQuery with Laravel to broadcast messages.

Kerimg's avatar

I didn't mean to select a best answer. Mistake on mobile, sorry.

@jekinney could you point me to said series?

@jimmck what's ZMQ?

Kerimg's avatar

@jekinney unfortunately I can't run node on our servers, which is why I was hoping using Ratchet (a PHP Websockets library) would be possible. Ideally in a decently integrated way.

Thanks anyway, though.

pyxl's avatar

You can use Brainsocket. It's an wrapper for Ratchet. I use it on my work for an Help-Desk System, and it works great :)

It's very easy and works with Laravel 5. But i think the project is dead :/

jimmck's avatar

@Kerimg ZMQ is a mature Message Queue library. It has a robust socket protocol. http://zeromq.org

PHP extensions ready to go.

http://php.net/manual/en/class.zmq.php

Here is a simple Blade file to setup the JS Side.

<!doctype html>
<html>
<head>
    <title>Coverage Category</title>
    <link rel="stylesheet" href="assets/css/main.css">
    <link rel="stylesheet" href="assets/css/alertify.css" />
    <link rel="stylesheet" href="assets/css/themes/default.css" />
    <link rel="stylesheet" href="assets/css/components/comptable.css"/>
</head>
<body>
    <script src="assets/js/vue/vue-1-13.js"></script>
    <!--script-- src="assets/templates/lissa.html"></script-->
    <script src="assets/js/DJWebUtils.js"></script>
    <script src="assets/js/alertify.js"></script>
    <script src="assets/js/ajax.js"></script>
    <script src="assets/js/types.js"></script>
    <script src="assets/js/fyi.js"></script>
    <script src="assets/js/coverage_category.js"></script>
    <script src="assets/js/autobahn.min.js"></script>

    @include('coverage::components.ListBox')
    @include('coverage::components.lissa')
    @include('coverage::components.Table')

    @yield('cat-content')

   <script>
    (function() {
        if ('requestIdleCallback' in window) {
            // Use requestIdleCallback to schedule work.
            fyi('Have idle callback available...');
        } else {
            // Do what you’d do today.
            fyi('idle callback is NOT available...');
        }

        var conn = new ab.Session('ws://localhost:8080',
            function() {
                conn.subscribe('cvg_cat', function(topic, data) {
                    // This is where you would add the new article to the DOM (beyond the scope of this tutorial)
                    //console.log('New article published to category "' + topic + '" : ' + data.title);
                    fyi(data);
               });
            },
            function() {
                console.warn('WebSocket connection closed');
            },
            {'skipSubprotocolCheck': true}
        );

        // Set default event handlers here.
        //debugger;
        startUp();
        index();    // initial load of select box.
    })();

    var name;

        function netInfo()
        {
            chrome.system.getNetworkInterfaces(function(networkIfaceArray){
                for(var i = 0; i < networkIfaceArray.length; i++){
                    var iface = networkIfaceArray[i];
                    console.log("name : "+iface.name+
                                    " ; address : "+iface.address+
                                    " ; prefixLength : "+iface.prefixLength);
                }
            });
        }
    </script>
</body>
</html>

A quick PHP Message Pusher.

<?php
use React\EventLoop\Factory;
use React\ZMQ\Context;
use App\lib\push\Pusher;

require dirname(__DIR__) . '/vendor/autoload.php';
$loop = Factory::create();
$pusher = new Pusher;
// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array ($pusher, 'onBlogEntry'));
// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(new Ratchet\Http\HttpServer(new Ratchet\WebSocket\WsServer(new Ratchet\Wamp\WampServer($pusher))), $webSock);
$loop->run();

Command module called by Laravel controller, sending update via ZMQ & running Message Pusher.

    class UpdateCvgCategory extends DbCommand implements IDbCommand
    {
        /*
         * @param $id int
         * @param $shortName String
         * @param $longName String
         */
        public function exec($id, $shortName, $longName)
        {
            $ret = null;
            try {
                $this->doThrow();
                $m = new CoverageCat($this->sql); // Call Model.
                $ret = $m->update($id, $shortName, $longName);
                $ret = new Message($ret, Message::STATUS_OK, 200);   // Record updated message.
                $this->push($ret->toString());
            } catch (InvalidArgException $e) {
                $ret = $e;
            } catch (DBConnectionException $e) {
                $ret = $e;
            } catch (SQLException $e) {
                $ret = $e;
            } catch (\Exception $e) {
                $ret = $e;
            } finally {
                $this->close();

                return $ret;
            }
        }

        protected function push($msg)
        {
            // This is our new stuff
            $context = new ZMQContext();
            $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
            $socket->connect("tcp://localhost:5555");
            $socket->send($msg);
        }
    }
sanjaykumarwebs's avatar

@jimmck , can u please tell me that Ratchet is secure solution or not? even I like this more instead of Pusher as everybody know that Pusher is third party and paid too that's why!

Please or to participate in this conversation.