Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Yii2 Websocket Laravel Package

morozovsk/yii2-websocket

Yii2 WebSocket extension for adding real-time communication to PHP applications. It helps run a WebSocket server, manage connections and messages, and push live updates to clients for chat, notifications, and dashboards, with straightforward Yii2 integration.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Yii2 console-side package, not a Laravel one. It wraps morozovsk/websocket (a dependency-free, stream_select-based PHP WebSocket server) in a yii\base\Component plus a console command. As a Laravel developer your realistic entry points are:

  1. You maintain/adjacent a Yii2 app that needs push notifications, and you want the smallest possible server.
  2. You're porting knowledge, and want to see how a pre-Swoole PHP event loop was wired into a framework.

It will not composer require cleanly into a Laravel skeleton — it extends yii\base\Component, expects Yii::$app and a console entry script, and will fatal on class resolution. Install it inside a Yii2 app:

composer require morozovsk/yii2-websocket

Look at these first, in this order:

  • vendor/morozovsk/websocket/ — Daemon, WebsocketServer, and the connection object. This is the actual engine; the Yii2 package is ~200 lines of glue.
  • vendor/morozovsk/yii2-websocket/src/ — the Component (reads config, constructs the server) and the handler base class. The base class signature tells you exactly what onOpen / onMessage / onClose receive.
  • README.md — the config array example is the whole documentation.

Minimal working setup (console config, config/console.php):

'components' => [
    'websocket' => [
        'class'    => 'morozovsk\websocket\Component', // verify FQCN in src/
        'host'     => '0.0.0.0',
        'port'     => 8081,
        'handlers' => [
            'onOpen'    => 'app\websocket\OpenHandler',
            'onMessage' => 'app\websocket\MessageHandler',
            'onClose'   => 'app\websocket\CloseHandler',
        ],
    ],
],

Then a handler class extending the package base:

namespace app\websocket;

class MessageHandler extends \morozovsk\websocket\Handler // verify base FQCN
{
    public function run($connection, $data)
    {
        // $connection->send(json_encode(['echo' => $data]));
    }
}

Launch it from the Yii2 console (typically ./yii websocket/start, confirming the command ID in src/commands/), and smoke-test with wscat -c ws://localhost:8081.

First use case: a one-way notification channel — Laravel (or any producer) writes to Redis, the Yii2 process reads and pushes to connected clients. Keep it that simple; the package gives you no routing, no auth, no persistence.

⚠️ Handler/command class names above follow the 2016 layout. Verify against vendor/ before copy-pasting; the README is the only spec.

Implementation Patterns

One handler class per event, registered in config. The handlers array keys must match the event names the Component looks for. Logic lives in the handler's run() (or onMessage), which gets the connection and the raw payload.

Connection state. There's no session object. Use the connection instance as the identity (spl_object_hash($connection) or a public property you tack on) and keep your own array $clients in the handler, or in a shared singleton if handlers are instantiated per-event:

class MessageHandler extends Handler
{
    public function run($connection, $data) {
        $msg = json_decode($data, true);
        if (($msg['type'] ?? null) === 'subscribe') {
            // $this->rooms[$msg['channel']][$id] = $connection;
        }
    }
}

Broadcast vs. targeted send. Broadcast means iterating whatever registry you built and calling $connection->send(...) per connection. There is no built-in pub/sub — you are the broker.

The Laravel ↔ Yii2 bridge. Do not put business logic in the handler. Three viable patterns, in order of preference:

  1. Redis pub/sub (best). Laravel publishes on model events ($redis->publish('chat.42', $json)); the Yii2 process runs a second, non-blocking socket in the same select() loop subscribed to those channels. This requires touching the underlying morozovsk/websocket loop — the Yii2 package does not expose a tick hook.
  2. Polling a Redis list/queue on a timer. Simpler if the loop exposes any periodic callback; otherwise fork a reader process that writes to a stream_socket_pair the server selects on.
  3. Internal HTTP control endpoint. Laravel posts to a small /push route; ugly, but the least invasive and easiest to reason about when debugging.

Authentication. The handshake carries no Laravel session. Mint a short-lived signed token in Laravel (encrypt() a user_id|expiry payload, or a JWT), pass it as a query string param, and validate it in onOpen without hitting the Laravel DB synchronously — decode locally or call back once and cache. Reject by closing immediately.

Lifecycle management. Prefer supervisor over the package's built-in daemonize option: you get restart-on-crash, log capture, and a sane stop signal. autorestart=true, stopsignal=TERM, and a stopwaitsecs long enough for the process to drain.

Scaling. One process = one event loop = one CPU core and one connection table. Beyond a few thousand clients you need SO_REUSEPORT + multiple processes and sticky routing, or a Redis fan-out layer so each process sees every message. Neither is provided.

Deployment. Run it as a sidecar container next to PHP-FPM, not inside the web container. Put nginx in front for wss:// termination — this package speaks plain ws:// only.

Gotchas and Tips

It's from June 2016 and it shows. No PHP 8 support: expect dynamic-property deprecations, and possibly each()/create_function in the underlying library. Pin the runtime to PHP 7.x, or budget a patch pass. 94 stars means nobody is coming to fix it for you — treat it as vendored code you own.

Blocking calls freeze every client. The whole server is one stream_select() loop. A synchronous PDO query, a file_get_contents() to an API, or a sleep() stalls all connections. Every handler must be non-blocking or fast-and-local. This is the single most common way these servers die under load.

Yii2 console bootstrap cost. The process loads the full framework into memory and holds DB connections open for days — expect "MySQL server has gone away" the first time a query fires after idle. Either don't query, or reconnect defensively before each use.

Handler config is silently forgiving. A typo in a handlers key means that callback never fires — no error, no log. If messages vanish, dump the handler map at boot and diff it against the event names in the Component source.

Debugging toolkit:

  • Run in the foreground during development (daemonize = false or equivalent) so echo/var_dump reaches your terminal.
  • wscat -c ws://host:port for a raw client; write a 10-line Node ws script for scripted multi-client tests.
  • ss -tlnp | grep 8081 to confirm the listener; empty means the command never reached run().
  • ps aux | grep yii after a crash — daemonized children orphan easily; supervisor masks this, which is why you should use it.

Frame size and encoding. Check the underlying library's max frame length and whether it handles fragmented frames and ping/pong. If not, implement a heartbeat in your own code and close on idle; proxies and mobile networks drop silent connections without telling either side.

Extension points that actually work: subclass the handler base (override the event methods), keep shared state in a singleton registered in the Yii2 container, and reach into morozovsk/websocket for per-connection send()/close(). Anything deeper — TLS, backpressure, per-message deflate, metrics — means forking the library.

Sanity check before you commit. If this is a greenfield Laravel service, the right answer is Laravel Reverb (first-party, actively maintained, same Redis pub/sub model, real auth integration), Soketi, or Ratchet if you must stay in-process PHP. Use morozovsk/yii2-websocket only when you're already inside a Yii2 codebase and the alternative is writing the select() loop yourself. The main thing worth stealing from this package is the shape of the config: host/port/handlers-in-a-map is a clean way to wire an event loop into a framework's container.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin