Installation:
composer require codememory/ws-server-bundle
Ensure Codememory\WebSocketServerBundle\WebSocketServerBundle::class is registered in config/bundles.php.
Basic Configuration (config/packages/codememory_websocket_server.yaml):
codememory_websocket_server:
server:
adapter: "Swoole"
host: "0.0.0.0" # Expose to LAN if needed
port: 8079
First Use Case:
// src/WebSocket/EventListeners/TestHandler.php
namespace App\WebSocket\EventListeners;
use Codememory\WebSocketServerBundle\Interfaces\MessageEventListenerInterface;
use Codememory\WebSocketServerBundle\Interfaces\MessageInterface;
class TestHandler implements MessageEventListenerInterface
{
public function handle(MessageInterface $message)
{
$data = json_decode($message->getData(), true);
// Process $data (e.g., broadcast to clients)
$message->send('ACK: ' . json_encode($data));
}
}
codememory_websocket_server:
event_listeners:
- { event: "TEST", listener: "App\WebSocket\EventListeners\TestHandler" }
Start the Server:
php bin/console codememory:websocket:server:start
Test with a WebSocket client (e.g., browser JS or wscat):
wscat -c ws://localhost:8079
> {"event": "TEST", "data": {"test": "payload"}}
Event-Driven Architecture:
config/packages/codememory_websocket_server.yaml under event_listeners.
Example for multiple events:
event_listeners:
- { event: "CHAT_MESSAGE", listener: "App\WebSocket\ChatHandler" }
- { event: "AUTH", listener: "App\WebSocket\AuthHandler" }
MessageEventListenerInterface:
class ChatHandler implements MessageEventListenerInterface
{
public function handle(MessageInterface $message)
{
$this->broadcastToRoom($message->getData(), $message->getClientId());
}
}
Client Management:
$message->send() to reply to a client or $message->broadcast() to send to all.
$message->send(json_encode(['status' => 'success']));
$message->getClientId() for targeted actions.Integration with Laravel:
WebSocketServer service into controllers/services:
use Codememory\WebSocketServerBundle\WebSocketServer;
class ChatController
{
public function __construct(private WebSocketServer $wsServer) {}
public function sendNotification()
{
$this->wsServer->broadcast('NOTIFICATION', ['message' => 'Hello!']);
}
}
onOpen in Swoole).Configuration Overrides:
# config/packages/codememory_websocket_server.yaml
server:
host: "%env(WSS_HOST)%"
port: "%env(int:WSS_PORT, 8079)%"
Scaling:
Frontend Integration:
Socket.IO (with fallback) or native WebSocket API:
const socket = new WebSocket('ws://localhost:8079');
socket.onmessage = (event) => console.log(JSON.parse(event.data));
socket.send(JSON.stringify({ event: "TEST", data: { foo: "bar" } }));
Authentication:
onOpen handler in Swoole config to validate tokens:
codememory_websocket_server:
config:
swoole:
onOpen: App\WebSocket\SwooleEventHandlers::onOpen
// App\WebSocket\SwooleEventHandlers
class SwooleEventHandlers
{
public static function onOpen($server, $request)
{
$token = $request->get['token'];
if (!self::validateToken($token)) {
$server->close($request->fd);
}
}
}
Logging:
MessageInterface to log events:
$logger = app(\Psr\Log\LoggerInterface::class);
$logger->info('WebSocket event', ['event' => $message->getEvent(), 'data' => $message->getData()]);
Testing:
ReactPHP or Guzzle to mock WebSocket connections:
$client = new \React\Socket\Connection('ws://localhost:8079');
$client->send(json_encode(['event' => 'TEST']));
Swoole Dependencies:
ext-swoole is installed (pecl install swoole). The bundle will not work without it.
sudo apt-get install php-swoole # Debian/Ubuntu
Configuration Overrides:
config/bundles.php, ensure the bundle is not auto-registered by Flex to avoid conflicts.config key in YAML is not merged with defaults—explicitly define all Swoole settings:
config:
swoole:
worker_num: 8
task_worker_num: 4
Event Naming:
"TEST" vs. "test"). Use constants for consistency:
class EventNames {
public const CHAT = 'CHAT_MESSAGE';
}
Connection Management:
onClose in Swoole config to clean up resources:
config:
swoole:
onClose: App\WebSocket\SwooleEventHandlers::onClose
Cross-Origin Issues:
location /ws/ {
proxy_pass http://localhost:8079;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
add_header 'Access-Control-Allow-Origin' '*';
}
Logs:
config:
swoole:
log_file: "/var/log/swoole.log"
log_level: 7 # DEBUG
storage/logs/laravel.log).Common Errors:
Class not found: Ensure listeners are autoloaded (run composer dump-autoload).lsof -i :8079).try {
$data = json_decode($message->getData(), true);
} catch (\Throwable $e) {
$message->send(json_encode(['error' => 'Invalid payload']));
}
Development Workflow:
php bin/console codememory:websocket:server:restart
swoole:alpine images and expose ports correctly:
RUN pe
How can I help you explore Laravel packages today?