symfony/light-sms-notifier
Symfony Notifier integration for LightSms, letting you send SMS notifications through the LightSms API. Configure it with a simple DSN containing your login, token, and sender phone number to start delivering text messages from your Symfony app.
Architecture fit
symfony/light-sms-notifier is not a Laravel package — it is a Symfony Notifier bridge (a transport factory plus a LightSmsTransport that speaks the LightSms HTTP API). Its only real integration surface is the symfony/notifier component: a DSN, a transport factory registered on Transport, and a Notifier that dispatches SmsMessage objects. That means the architectural question is not "does this fit Laravel?" but "do we want to adopt symfony/notifier as a second notification abstraction alongside Laravel's own Illuminate\Notifications?"
For a TPM the honest framing is:
Integration feasibility
| Dimension | Assessment |
|---|---|
| Native Laravel support | None. No service provider, no config file, no facade. You write the glue. |
| Dependencies added | symfony/notifier, symfony/http-client (or a PSR-18 client), symfony/options-resolver; transitively more if Messenger is used. |
| Effort to first send | Low — roughly a day for a spike: bind Notifier in a service provider, register the LightSmsTransportFactory on a Transport instance, construct the DSN from config/services.php. |
| Effort to production-grade | Moderate — queueing, retries, failure handling, credential handling, and observability are all yours to build. |
| Testability | The transport is HTTP-based; HttpClientInterface can be mocked, but you'll be asserting against Symfony's test doubles rather than Laravel's Notification::fake(). |
The critical feasibility constraint is version skew. Release lines track Symfony majors: the 8.1 line requires PHP ≥ 8.4, the 7.x line targets PHP ≥ 8.2, and 6.4 is the LTS. Laravel's own symfony/* constraints (Console, HttpFoundation, Finder, etc.) are pinned per Laravel major, so pulling symfony/notifier v8 into a Laravel 11/12 app on PHP 8.2–8.3 will either fail resolution or force you onto an older bridge line. Practical guidance: pin the bridge to the line that matches your Laravel's existing Symfony component version, and treat this as a hard constraint in the spike, not a footnote.
Technical risk
LOGIN:TOKEN in a single string. Anything that dumps configuration — config:cache artifacts, exception traces from a failed transport, HTTP client debug logs — can leak the token. Mitigation is straightforward (build the DSN at runtime from separate env vars, scrub logs) but it must be an explicit checklist item.symfony/symfony; releases are cut automatically with each Symfony release and the repo will not disappear even if the vendor relationship ends. Support continuity is decent; feature responsiveness for LightSms-specific issues is not.Key questions
Stack fit
Assume Laravel 11/12, PHP 8.2–8.4, Redis queues, Horizon. The package slots in as a transport library, not as a framework feature. The workable pattern:
LightSmsServiceProvider that builds a Transport with only the LightSmsTransportFactory registered, exposes it as a singleton, and constructs the DSN from config('services.lightsms.*') so no token ever lives in a cached config artifact as part of a URL.LightSmsClient application-level wrapper with a deliberate method surface (send(string $to, string $body, ?string $from): Result) that returns a small result object rather than leaking Symfony exceptions into domain code.LightSmsChannel) or a Mailable-style job that calls the wrapper. This keeps Illuminate\Notifications as the developer-facing abstraction and makes the Symfony Notifier purely an implementation detail — which is exactly the right trade. Application code never imports Symfony\Component\Notifier\*.tries, backoff, and a failed() handler, so retry semantics are Laravel's, not the vendor's.Migration path
Treat this as an additive capability, not a migration. Sequence:
SmsSender interface in the application and ship a logging/fake implementation. Get the notification flows, templates, and tests written against it.Compatibility
symfony/http-client does not conflict with any Guzzle/HTTP layer already installed; if it does, prefer binding a PSR-18 client the bridge can consume.sync; retry and serialization behavior differ.Sequencing
Phase 0: vendor + compliance check (sender IDs, opt-out handling, data residency). Phase 1: abstraction + fake sender + tests. Phase 2: bridge spike and segment/encoding validation. Phase 3: queued delivery + failure handling + observability. Phase 4: flagged rollout, one flow at a time. Roughly 2–3 engineer-weeks for a production-grade first flow, most of which is queueing, observability, and testing — not the bridge itself.
Maintenance
Low but non-zero. The package itself will be maintained by Symfony; your maintenance burden is the glue: the service provider, the wrapper, the DSN construction, and the pinned version matrix. That glue is small enough that one engineer can own it, but it must have a named owner — orphaned integration glue is the most common failure mode for packages like this. Track Symfony release notes for the notifier component; expect routine, low-surprise updates.
Support
Split support model, and say so explicitly to stakeholders: Symfony core supports the bridge; LightSms supports delivery. When an SMS fails to arrive, the first-line triage is vendor-side (account balance, sender-ID approval, carrier filtering, regional restrictions), not code. The 3-star / 0-dependent profile means you cannot lean on community troubleshooting — establish a direct LightSms support contact and confirm SLA expectations before launch. Escalation to Symfony is via the main symfony/symfony issue tracker and should be expected to be slow for anything vendor-specific.
Scaling
The bridge is a thin HTTP client; it will not be your bottleneck. Scale concerns live in four places:
Failure modes
| Failure | Symptom | Mitigation |
|---|---|---|
| Vendor auth failure | All sends throw on 401 | Health-check job that sends one message per day to an internal number; alert on failure. |
| Vendor outage / latency | Queue backlog grows | Separate queue, bounded retries with exponential backoff, circuit breaker or feature flag to disable non-critical flows. |
| Invalid sender ID / unregistered originator | Rejections on specific countries | Pre-validate per-country sender IDs during Phase 0; maintain a supported-country allowlist in config. |
| Encoding / segment blowout | Messages truncated or billed 3× | Enforce GSM-7 vs Unicode validation in the wrapper; log segment count. |
| Token leakage via logs | Credential in exception traces or config cache | Runtime DSN construction, log scrubbing rules, rotate token on any suspicion. |
| Silent non-delivery | API returns 2xx, handset never receives | Accept that the bridge almost certainly gives no delivery receipts; instrument vendor dashboard checks or add vendor callback integration as explicit scope. |
| Dependency drift | Composer resolution breaks on Laravel upgrade | Pin versions; add the bridge to the upgrade checklist. |
Ramp-up
Ramp-up cost is low for an engineer familiar with Laravel service providers and queues — half a day to understand, one day to build the wrapper and tests. The non-obvious learning is domain knowledge, not code: SMS segment economics, sender-ID registration per country, opt-out and consent obligations, and vendor-specific error taxonomy. Budget a short knowledge-share doc covering the DSN construction, the wrapper contract, triage steps, and the supported-country list. For stakeholders, the honest pitch is narrower than "SMS in weeks": this is one vendor adapter, ~2–3 engineer-weeks to production-grade for a first flow, with vendor selection as the preceding and larger decision.
How can I help you explore Laravel packages today?