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

Sms Laravel Package

xi/sms

A Laravel package for sending SMS messages through a unified API with configurable gateway drivers, queue support, and simple notification integration.

View on GitHub
Deep Wiki
Context7

Getting Started

xi/sms is a small, framework-agnostic SMS abstraction: a message value object plus a gateway contract you implement per provider. It is not a Laravel package — there is no service provider, facade, config file, or notification channel — so "getting started" means wrapping it yourself in about 50 lines. With 10 stars, zero dependents, and no recent activity, treat it as a reference interface for a legacy codebase, not a library to build a new product on.

  1. Check installability before anything else. The package predates modern PHP; its composer.json constraint will likely block PHP 8.x.

    composer show xi/sms --all          # inspect versions + PHP constraint
    composer why-not php 8.2            # see the exact conflict
    

    On a legacy PHP 7.x app, composer require xi/sms is fine. On PHP 8, either fork and patch the constraint (after reading the source for removed functions) or skip it — the abstraction is small enough to reproduce.

  2. Read the source in this order. There is no documentation worth relying on beyond the README:

    • the gateway contract (the GatewayInterface-style class under src/) — this is the only real extension point;
    • the message/value-object class — note whether it validates from, to, and body or just holds strings;
    • any bundled gateways — these show the expected request shape and whether they use cURL, file_get_contents, or an HTTP client;
    • the test suite — the fastest way to learn intended usage.
  3. Create the Laravel seam. Keep package types out of your domain code:

    // app/Contracts/SmsSender.php
    interface SmsSender { public function send(string $to, string $body, ?string $from = null): void; }
    
    // app/Services/XiSmsSender.php
    final class XiSmsSender implements SmsSender
    {
        public function __construct(private \Xi\Sms\Gateway\GatewayInterface $gateway) {}
    
        public function send(string $to, string $body, ?string $from = null): void
        {
            $this->gateway->send(new \Xi\Sms\SmsMessage($from, $to, $body));
        }
    }
    

    Bind the contract in AppServiceProvider (or a dedicated SmsServiceProvider) and pull credentials from config/services.php / env — never hardcode them.

  4. First use case: one transactional path only — OTP or "order shipped" — dispatched from a queued job. That exercises config, the gateway, error handling, and testing without over-engineering.

Implementation Patterns

  • Adapter first, gateway second. Your SmsSender contract is the stable API; the xi gateway is an implementation detail. This lets you swap in a maintained provider later without touching call sites.
  • Driver factory from config. If you support more than one provider, resolve the gateway in a small factory keyed by config('sms.default'), mirroring Laravel's manager pattern. Instantiate lazily (in the binding closure), not at boot.
  • Message building is your job. Put body construction (templates, locale, placeholders) in a dedicated class or Blade/Markdown view. The package will not template, truncate, or encode for you.
  • Queue everything. Send from a ShouldQueue job or a queued notification with $tries, $backoff, and $timeout set. SMS gateways are external HTTP calls; doing this synchronously in a request is the most common production mistake.
    final class SendSms implements ShouldQueue
    {
        public $tries = 3;
        public $backoff = [10, 60, 300];
        public function __construct(public string $to, public string $body) {}
        public function handle(SmsSender $sms): void { $sms->send($this->to, $this->body); }
    }
    
  • Test double over mocking. Implement the gateway contract (or your SmsSender) with an in-memory fake that records messages, and rebind it in TestCase::setUp. Assert on the fake rather than on HTTP.
    $this->app->instance(SmsSender::class, $fake = new FakeSmsSender());
    // ... act ...
    $fake->assertSentTo('+36301234567', fn ($body) => str_contains($body, 'kód'));
    
  • Standardize failures at the boundary. Catch whatever the gateway throws (often generic \Exception or a false return) and rethrow as one retryable SmsDeliveryException vs. a permanent InvalidRecipientException. Laravel's retry logic can then distinguish $this->release() from $this->fail().
  • Log without leaking PII. Log provider, message ID, and status — not full bodies or phone numbers (mask to last 4 digits).
  • Multi-gateway / failover. Only worth it past a volume threshold: primary gateway in a try, secondary in catch, with a circuit breaker to avoid hammering a dead provider.

Gotchas and Tips

  • License is NOASSERTION. GitHub could not classify it; open the LICENSE file before shipping in a commercial product. This is a legal blocker, not a formality.
  • Maintenance risk is the headline. Zero dependents and a decade-old codebase mean no security patches and no PHP 8 fixes. Expect each(), curly-brace string offsets, missing return types, and possibly mcrypt in gateway code. Run the test suite on your target PHP version before committing.
  • No HTTP abstraction. Bundled gateways likely build URLs or use file_get_contents/raw cURL. That means no timeouts by default, no connection reuse, and no way to intercept in tests. If you keep the package, inject your own transport or confine it behind your adapter.
  • Encoding and length are on you. GSM-7 gives 160 chars; a single emoji or accented character forces UCS-2 and drops you to 70 chars per segment. Decide on transliteration vs. multi-part before you build templates, and validate length in your SmsSender.
  • Normalize phone numbers upstream. The package almost certainly does no E.164 validation. Use a phone-number library in your form request or a Cast, and reject invalid numbers before they reach a paid gateway.
  • No idempotency or dedupe. Queued retries can double-send and double-bill. Store a dedupe key per logical message (e.g., order:123:shipped) and check it in the job.
  • Config cache trap. If you resolve the gateway in a provider's register() using env() directly, php artisan config:cache will freeze stale values. Go through config() only.
  • Extension points are minimal but sufficient: implement the package's gateway interface to add a provider, and implement/extend the message class only if a provider needs extra payload fields. Everything else (retries, logging, templating, failover) belongs in your Laravel layer, not the package.
  • Verdict: for a greenfield Laravel app, skip it — you'd write the same interface yourself in an afternoon and control the transport. Keep it only if you're maintaining an existing integration and cannot yet extract the gateway behind your own contract.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core