symfony/rocket-chat-notifier
Symfony Notifier integration for Rocket.Chat. Configure a webhook DSN with access token and channel, then send ChatMessages with custom payloads and attachments to control bot name, avatar, channel, and message content.
What the package actually is
symfony/rocket-chat-notifier is a transport bridge for the Symfony Notifier component, not a general-purpose Rocket.Chat SDK. It contributes one thing: a rocketchat:// DSN scheme that maps a webhook URL into a Transport implementing ChatterInterface, plus a RocketChatOptions value object for alias, emoji, avatar, channel, and attachments. All actual message delivery goes through Rocket.Chat Incoming Webhooks — there is no REST API client, no room management, no user lookup, no WebSocket support.
Architecture fit (Laravel)
Notification::channel, toRocketChat()); this package belongs to a parallel, Symfony-native notification stack. There is no Laravel bridge, service provider, or facade. Integration means running Symfony Notifier inside Laravel as a sidecar service, then either using it directly ($chatter->send(new ChatMessage(...))) or wrapping it in a custom Laravel channel.messenger/notifier YAML; in Laravel you must manually instantiate RocketChatTransportFactory, call create($dsn), and bind the resulting transport/chatter into the container. This is ~40 lines of glue that you now own.symfony/notifier + symfony/http-client into a Laravel app is not free: it adds Symfony components that may collide with Laravel's own pinned symfony/* constraints (Laravel 10 → ^6.4, Laravel 11/12 → ^7.x), and it introduces a second notification abstraction the team must learn.Http::withOptions()->post($webhookUrl, $payload) is roughly 30–50 LOC, has zero dependency risk, and matches the framework idiom. This package's real value is not capability — it is standardization, the options object, and Symfony's maintenance/security process.Integration feasibility
rocketchat://WEBHOOK_ID%2FWEBHOOK_TOKEN@host?channel=NAME.%2F). A plain copy-paste of the webhook URL will silently fail auth — this is the single most likely onboarding defect.channel in the DSN is advisory; per-message channel override via payload only works if a custom Incoming Webhook Script is installed on the Rocket.Chat side. Without that script, channel and rich formatting are effectively fixed/limited. That script is JavaScript deployed in Rocket.Chat admin — a second artifact your team must own, review, and version.RocketChatOptions($attachments, $payload) constructor is positional and has two accepted shapes ("for backward compatibility both usages are valid"), and payload.text / payload.attachments are silently overridden by ChatMessage subject and constructor attachments. This is a correctness footgun that will produce "why is my title missing" tickets.Technical risk
symfony/symfony monorepo — usage is measured by the monorepo, not this repo. However, it does mean near-zero public Q&A, blog posts, or Laravel-specific examples; you will be reading Symfony source, not tutorials.Key questions to resolve before committing
Http::post wins on total cost of ownership.symfony/* constraint baseline today, and does composer require resolve cleanly or force a transitive bump?Stack fit assessment
| Criterion | Verdict |
|---|---|
| Laravel 10 (Symfony 6.4 components) | Workable; pin symfony/notifier ^6.4, test resolution carefully |
| Laravel 11/12 (Symfony 7.x) | Best fit; aligns with ^7.x bridge releases |
| Laravel 9 or older | Not recommended — PHP/Symfony floor conflicts |
| PHP 8.1–8.3 | Fine for 6.4/7.x bridges; Symfony 8 line needs PHP 8.4 |
| Team Symfony fluency: low | Adds a second notification paradigm — prefer an in-house channel |
Recommended integration shape (if we proceed)
App\Contracts\ChatNotifier with send(string $channel, string $text, array $fields = []), and implement it once over Symfony's ChatterInterface. This isolates the dependency so it can be swapped for Http::post in an afternoon if the bridge disappoints.config/services.php (Laravel-idiomatic) rather than adding a bespoke config/rocket_chat.php. Bind as a singleton; keep the DSN out of code and out of any config cache dump by reading it at resolve time.%2F separator, assert the host resolves. Fail fast in CI with a smoke-test webhook channel.ShouldQueue, $tries = 3, exponential backoff, failed() → log/alert). Never call the chatter synchronously from a request or from inside a DB transaction.ops/rocketchat/incoming-webhook.js, with a documented deploy step and a note in the runbook.Migration path & sequencing
composer.lock, confirm a real webhook round-trip from a tinker session, confirm whether the custom script is required for our target channel(s). Decision gate: proceed vs. build in-house.Exit strategy (state this up front): because all calls funnel through the ChatNotifier port, replacing the bridge with a native HTTP channel is a single-file change. That caps the blast radius of the low adoption signal.
Maintenance
config:cache + deploy on every environment, including any local/staging stacks that send to shared channels.Support
symfony/symfony monorepo issue tracker, not this repo; expect Symfony-idiomatic answers and no Laravel-specific guidance. Security issues follow Symfony's coordinated disclosure and CVE process — this is a genuine advantage over hand-rolled webhook code.ChatterInterface/RocketChatOptions semantics. Mitigate with the port abstraction and a short ADR documenting the DSN format, the %2F encoding trap, and the options precedence rules.Scaling
channel override requires the custom script, that script becomes a scaling and correctness dependency — test it under load.Failure modes
| Mode | Symptom | Mitigation |
|---|---|---|
Malformed DSN (unencoded /) |
Auth failure on every send; 401/403 | Boot-time DSN validation; CI smoke test |
| Webhook disabled/rotated | 404/401, all traffic dead silently | Alert on sustained send failures; healthcheck message to a canary channel |
| HTTP 200 with error body | Appears healthy, nothing delivered | Log response body; periodic synthetic message + absence detection |
| Rate limit (429) | Dropped bursts | Queue + backoff + per-channel rate limiter |
| Network timeout | Job retries, duplicate posts | Idempotency via a dedupe key in the message text/field; bounded retries |
| Options precedence surprise | Missing title/text in message | Single message builder; unit tests on output shape |
| Rocket.Chat down | Queue backlog | Bounded queue depth, dead-letter, alert on oldest-job age |
| Webhook script error (if used) | Payload silently dropped or reformatted | Script unit test against sample payloads; version it |
Ramp-up
Transport, TransportFactory, ChatterInterface, ChatMessage, options precedence) and on the DSN encoding trap. No Laravel-native docs exist, so onboarding must be internal documentation, not a link to the README.TPM recommendation
Treat this as a low-risk, low-value dependency: technically sound and well-maintained upstream, but it delivers ~150 lines of equivalent capability while adding a parallel notification abstraction to a Laravel codebase. Approve it only if Rocket.Chat is a durable, first-class channel and the team wants Symfony's security/upgrade process behind it. Otherwise, build a native Laravel channel (~1 dev-day, zero dependency risk). Either way, gate on the Phase 0 spike and mandate the ChatNotifier port so the decision remains reversible.
How can I help you explore Laravel packages today?