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

Clank Bundle Laravel Package

jdare/clank-bundle

Clank Bundle integrates the Clank PHP Slack bot library with your framework, adding configuration and service wiring so you can register bots and handle Slack events without manual bootstrapping.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony 2.x bundle, not a Laravel package. Treat it as two things: (a) a turnkey WebSocket server for legacy Symfony 2.1–2.3 apps, and (b) a reference implementation of Ratchet + a topic/RPC dispatcher that you can port into a Laravel artisan command in an afternoon. Its actual value to a Laravel dev is the architecture — WAMP topic handlers as DI services, session-aware handshake, and a ZMQ "push from HTTP request → WS server" bridge — not the composer require.

Minimal steps in a Symfony 2 app:

  1. composer require jdare/clank-bundle (expect PHP 5.3/5.4-era constraints and Symfony 2.x components — this will not resolve against a modern Laravel composer.json).
  2. Register new Clank\Bundle\ClankBundle() in AppKernel, add a clank: block to config.yml for host/port and session options (read DependencyInjection/Configuration.php first — the keys changed between releases and the README lags).
  3. Write one topic class annotated @Topic("chat") with onSubscribe / onPublish / onClose, register it as a service tagged clank.topic.
  4. php app/console clank:server:start and connect with AutobahnJS.

First use case: a presence/notification channel. Subscribe a connection to a per-user topic on handshake, broadcast on state change, remove on close. That exercises the session provider, the topic tag, and the broadcaster — the three things you'll port.

Where to look first, in this order: the clank.topic tag compiler pass (shows how topic names are resolved), the topic dispatcher (the WAMP glue), the Symfony session provider (the auth story), and the server command (the React loop you'll reimplement). Skip the bundle's DI bootstrapping entirely when porting.

Implementation Patterns

One topic class per domain, registered as a service. The bundle scans tagged services for the @Topic annotation, so constructor injection works normally:

/**
 * @Topic("chat")
 */
class ChatTopic
{
    public function onSubscribe(ConnectionInterface $conn, $topic)
    {
        $topic->broadcast(['msg' => "{$conn->resourceId} joined"]);
    }

    public function onPublish(ConnectionInterface $conn, $topic, $msg)
    {
        $topic->broadcast(['msg' => $msg, 'from' => $conn->resourceId]);
    }

    public function onClose(ConnectionInterface $conn, $topic)
    {
        $topic->broadcast(['msg' => "{$conn->resourceId} left"]);
    }
}
services:
    acme.topic.chat:
        class: Acme\ChatBundle\Topic\ChatTopic
        arguments: ['@doctrine.orm.entity_manager']
        tags:
            - { name: clank.topic }

Authorize inside onSubscribe, not at the router. The session provider only proves identity at handshake time; per-topic authorization is your job. $conn->Session->get('user_id') is populated from the Symfony session cookie during the upgrade request. If you're porting to Laravel, that's the hook where you'd swap in a JWT-in-query-string or a signed-cookie SessionProvider.

Push from HTTP to the socket server. The bundle's push service lets a controller notify connected clients without the socket server making an outbound request — it publishes over ZMQ to the React loop, which then broadcasts to the topic. This is the pattern worth stealing: in Laravel, put a Redis PUBLISH in a controller/event listener and a React\ZMQ or clue/redis-react subscriber inside the artisan WS loop. Keep the message envelope identical on both ends (topic name + payload) so the loop is a dumb relay.

RPC handlers (@Rpc classes with onCall) are useful for request/response over WS — polling, "fetch my unread count" — but they give you a second RPC surface with no auth model of its own. Prefer topics plus a thin REST call unless you specifically need sub-100ms round trips.

Operational wiring: run the command under Supervisor with autorestart=true; front it with nginx using proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; and proxy_read_timeout 3600s; terminate TLS at nginx rather than in React.

Porting to Laravel — the whole bundle collapses into ~80 lines:

protected $signature = 'ws:serve {--port=8080}';

public function handle()
{
    $loop   = \React\EventLoop\Loop::get();
    $socket = new \React\Socket\SocketServer("0.0.0.0:{$this->option('port')}", [], $loop);
    $server = new \Ratchet\Server\IoServer(
        new \Ratchet\Http\HttpServer(
            new \Ratchet\WebSocket\WsServer(
                new \Ratchet\Wamp\WampServer(app(TopicDispatcher::class))
            )
        ),
        $socket,
        $loop
    );
    $server->run();
}

TopicDispatcher implements WampServerInterface and resolves topic names against a ['chat' => ChatTopic::class] map from a config file — that map replaces the bundle's annotation scan and is easier to reason about anyway.

Gotchas and Tips

  • It will not install into a modern Laravel. Symfony 2.x component conflicts plus PHP 5.x constraints. Don't fight it; copy the four files you care about. If you're on a legacy Symfony 2 app, pin the bundle and cboden/ratchet together and freeze that corner of the dependency tree.
  • @Topic names are a string contract with the JS client. A typo yields a silent no-op subscribe, not an error. Log the topic name in onSubscribe while developing.
  • Annotation scanning requires doctrine/annotations and a writable cache. In prod, the annotation reader cache goes stale after deploys — restart the process, don't just clear the app cache. This is the most common "my new topic doesn't exist" cause.
  • Long-running process, stale container. Entities/connections accumulate; the Symfony container is fully booted once and never reset. Periodically $em->clear() / DB::disconnect() in a timer, and always restart the server on deploy — there is no hot reload.
  • AutobahnJS needs skipSubprotocolCheck: true against this server, otherwise the connection is rejected for protocol mismatch. Clients written against other Ratchet examples will fail here first.
  • ZMQ push fails silently when the socket server is down. The HTTP request succeeds, the notification vanishes. Wrap the push in a try/catch that logs at error, and consider a Redis pub/sub fallback that survives server restarts.
  • Origin checking is config-driven and off by default in some releases. Set it explicitly. It's not a CSRF substitute; your handshake auth is the real control.
  • Debugging: clank:server:start -v surfaces Ratchet exceptions that otherwise die on the connection; attach a PSR-3 logger to IoServer in your port for the same visibility. Most "connection drops immediately" reports are an uncaught exception in onSubscribe.
  • Extension points, best to worst: custom SessionProvider (auth), custom router, replacing the topic dispatcher outright. Don't try to add middleware between Ratchet and the dispatcher — the bundle doesn't expose a clean seam there, and the DI wiring is the least documented part of the codebase.
  • Last release 2013, zero dependents. Budget for it being the thing you replace, not the thing you build on. Its durable ideas are topic-as-service, session-at-handshake, and HTTP→WS push; everything else is era-specific Symfony 2 ceremony.
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.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings