symfony/octopush-notifier
Symfony Notifier integration for Octopush, letting your app send SMS through Octopush's gateway. Configure the DSN with your login, API key, sender and SMS type (XXX low-cost, FR premium, or WWW world) to start delivering text messages.
Architecture fit. symfony/octopush-notifier is a transport bridge for the Symfony Notifier component, not a standalone SMS client. It ships two small pieces of surface area: an OctopushTransport (talks to the Octopush API) and an OctopushTransportFactory (parses the octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE DSN and instantiates the transport). Everything else — routing, channels, message building, retry strategy — belongs to symfony/notifier. For a Laravel codebase this is the central architectural fact: Laravel has no Notifier equivalent, so adopting this package means adopting a sliver of the Symfony component tree (symfony/notifier, symfony/http-client, symfony/event-dispatcher, symfony/mime) alongside Laravel's own Mail/Notification/Queue systems. Fit is therefore conditional and narrow: reasonable if the team already pulls Symfony components deliberately, poor if the goal is "an SMS driver for Laravel Notifications."
Integration feasibility. Two viable paths. (1) Thin adoption — install the package purely to reuse OctopushTransport, construct it manually or via a small Laravel service provider, and call send() with a Symfony\Component\Notifier\Message\SmsMessage. This gives you a maintained HTTP client for the Octopush API without buying into Notifier's routing. (2) Full adoption — stand up Notifier, a Transports registry, and channel policies inside Laravel, then treat Octopush as one transport among several. Path 1 is roughly a day of work; path 2 is a sprint and creates a parallel notification subsystem that competes with Laravel's native Notification facade — a long-term debt generator. Note the package has zero dependents and eight stars, so there is essentially no community evidence of Laravel-specific usage; the integration is unproven outside Symfony full-stack.
Technical risk. Low on code correctness (it is maintained under the symfony/* namespace with the standard release train and MIT license), moderate-to-high on ecosystem mismatch. The real risks are: a second HTTP client stack (symfony/http-client vs. Laravel's Guzzle-backed Http facade) meaning two sets of timeouts, retries, and telemetry; two notification abstractions with different templating, queuing, and channel semantics; and the DSN-in-env pattern clashing with Laravel's config/services.php convention. Vendor risk on Octopush itself (French provider, SMS route types XXX/FR/WWW) is a separate commercial question the package cannot answer. symfony/notifier v7.2 deprecated TransportFactoryTestCase, signalling the bridge's test scaffolding churns across majors — plan for minor pinning.
Key questions.
OctopushTransport only) or a notification system (full Notifier)? The answer changes scope by an order of magnitude.symfony/notifier dependency in composer.json for one SMS vendor, and does that survive the next framework upgrade?Stack fit. Weak by default, workable with discipline. Laravel shares Symfony's foundation (HttpFoundation, Console, VarDumper, ErrorHandler) but not Notifier or HttpClient by default. The package's own dependency footprint is small, but pulling symfony/notifier drags in symfony/http-client, symfony/event-dispatcher, symfony/mime, and transitively more. If the codebase already has symfony/http-client (some Laravel apps do via Mailer/Messenger transports), the marginal cost drops sharply. If it standardises on Guzzle, we are adding a second client.
Migration path. Sequence it as a containment exercise, not a framework adoption:
OctopushTransport directly with credentials from config/services.php; send a live SMS to a test number with each type (XXX, FR, WWW). Confirm error/exception behaviour on bad credentials, invalid number, and insufficient balance.OctopushSender interface in the app with one implementation delegating to the Symfony transport. Nothing outside this class may reference Symfony\Component\Notifier. This is the containment boundary and the thing that makes the vendor replaceable.tries/backoff, so Octopush latency never sits in a request cycle.Compatibility. Pin the package major to the Symfony minor that matches our PHP version — Symfony 5.4/6.4 for older runtimes, 7.x for PHP 8.2+, 8.x only on PHP ≥ 8.4. Verify Laravel's own Symfony-component pin does not conflict (composer why symfony/http-client and composer why symfony/notifier before install). Watch the TransportFactoryTestCase deprecation if we ever write tests against the factory; test against our wrapper instead and the churn is invisible.
Sequencing. Containment first (wrapper + interface + config), delivery second (queue, retries, logging), observability third (metrics on send success, latency, and DLR), and only then consider broadening to Notifier. If the team cannot commit to the wrapper boundary in step 2, stop — do not adopt.
Maintenance. The package itself is near-zero maintenance: it is release-train-managed with the rest of Symfony, changes are cosmetic ("no significant changes" across most releases), and MIT licensing removes legal friction. The maintenance cost lives one layer up — keeping symfony/notifier and symfony/http-client in step with Laravel's own Symfony pins across framework upgrades. Budget a small, recurring composer-conflict tax at each Laravel major rather than a large one-off.
Support. Effectively none from the ecosystem: 8 stars, 0 dependents, no Laravel-specific documentation, issues routed to the main symfony/symfony tracker where our problem will be a rounding error. Internal ownership is mandatory — one named engineer or team must own the wrapper, the credential rotation, and the Octopush account relationship. Octopush's own support is the real escalation path for delivery failures, and that is a commercial relationship, not an open-source one.
Scaling. Adequate within normal SMS volumes; SMS is neither high-throughput nor latency-critical compared with API traffic, and batching/queueing absorbs bursts. The constraints are external: Octopush account throughput limits, per-route pricing tiers (XXX low-cost vs FR premium vs WWW world — cost per message varies materially by route, which is a budget-model input, not an engineering one), and Laravel queue worker capacity. The Symfony transport is stateless, so horizontal scaling is a queue-worker concern, which Laravel handles well. No shared-state or connection-pool hazards.
Failure modes. Four to plan for: (1) credential/token expiry — surfaces as an auth exception at send time; needs a health check and alerting, not silent queue retries. (2) Insufficient balance / account suspension — Octopush returns an error that looks like a transient failure; without distinguishing it, retries burn and messages are lost, so classify errors into retryable and terminal before enqueuing. (3) Provider outage — no circuit breaker is provided; if SMS is business-critical, an interface-level fallback to a second provider (Twilio et al.) must be designed now, and the wrapper boundary is what makes that a config change rather than a rewrite. (4) Silent non-delivery — a 2xx from the API means "accepted," not "delivered"; without DLR polling or webhook ingestion we have no delivery truth. Decide explicitly whether delivery receipts are in scope. Finally, two HTTP stacks means two sets of timeouts and two sets of logs — standardise logging around the wrapper so on-call sees one line per send with the provider's message ID.
Ramp-up. Low for any PHP developer: the DSN is self-documenting and the wrapper is a handful of methods, so a mid-level engineer is productive in under a day. The non-obvious learning is the containment discipline (never let Symfony\...\Notifier types leak into controllers or jobs) and the error taxonomy (terminal vs. retryable, accepted vs. delivered). Both should be captured in a short internal README at the time of adoption — the upstream README will not teach them. Expect a half-day of onboarding for future maintainers if that document exists, and a genuinely unpleasant discovery process if it does not.
How can I help you explore Laravel packages today?