xi/sms-bundle
xi/sms-bundle adds SMS messaging to your PHP application, providing a configurable service for composing and sending text messages through your chosen gateway. A lightweight option for teams wanting to wire SMS notifications into an existing stack without heavy dependencies.
This bundle is a thin Symfony integration for the xi/sms library: it wires up a gateway service you can inject to send SMS messages. It is an old, low-traffic package (2 stars, 0 dependents, likely Symfony 2-era and unmaintained), so treat the first hour as a compatibility audit rather than a quick install.
composer.json for symfony/symfony and php constraints. If you are on Symfony 4+/Flex, you will almost certainly need to fork or vendor the bundle and adapt it (no AppKernel, no app/config/config.yml). On Symfony 2.x/3.x it should drop in.composer require xi/sms-bundle
Symfony 2/3: register new Xi\Bundle\SmsBundle\XiSmsBundle() in AppKernel.config.yml under the xi_sms key (the exact key is defined in the bundle's DependencyInjection/Configuration.php — read that file first). Typical shape:
xi_sms:
gateway: my_gateway
gateways:
my_gateway:
# provider-specific: api key, sender/from number, endpoint
DependencyInjection/Configuration.php → what config keys actually exist.DependencyInjection/*Extension.php → the service IDs and gateway aliases.Resources/config/*.xml|yml → the concrete gateway classes and their constructor args.vendor/xi/sms/src/... → the actual SmsService/Gateway interfaces you will code against.$message = new \Xi\Sms\SmsMessage('+358401234567', 'Hello from Xi');
$this->get('xi_sms.sms_service')->send($message);
Confirm the service ID with php app/console container:debug | grep -i sms before writing code — do not trust docs, there are none reliable.Wrap the bundle behind your own interface. Because this package is unmaintained, do not let Xi\Sms\* types leak across your codebase. Define a one-method SmsSender interface in your app and implement it with the bundle's service. Swapping providers (or the whole package) later becomes a one-class change.
interface SmsSender { public function send(string $to, string $body): void; }
class XiSmsSender implements SmsSender {
public function __construct(private $smsService) {}
public function send(string $to, string $body): void {
$this->smsService->send(new \Xi\Sms\SmsMessage($to, $body));
}
}
Send from a console command, not the request cycle. SMS providers are slow and rate-limited; a synchronous send in a controller blocks the user and fails loudly on provider timeouts. A command + queue (even a simple DB table) is the sane default:
// app/console sms:send {to} {body}
$output->writeln($this->get('app.sms_sender')->send($args['to'], $args['body']) ? 'sent' : 'failed');
Use one gateway per environment. Point xi_sms.gateway at a "log" or fake gateway in dev/test config and the real one in prod. If the bundle ships no fake gateway, write a trivial one implementing the Gateway interface and register it as a service — this doubles as your test double.
Batch/campaign sends: loop over recipients with a small sleep between sends to respect provider throttling, catch per-recipient exceptions so one bad number does not abort the batch, and persist a send log row (recipient, body hash, gateway response, timestamp) for reconciliation.
Integration points worth wiring:
kernel.exception or job-failure listener that alerts ops via SMS (dogfooding the bundle is a good smoke test).monolog channel tagged for the SMS service so provider errors land in a dedicated log file.Testing: unit-test your XiSmsSender against a mock of the bundle's service (or your fake gateway). Do not functional-test against a real provider in CI; assert on the message object (to, body) passed to the fake.
composer.json, vendor the source if it breaks, and budget for a rewrite if SMS becomes business-critical.container:debug, config:dump-reference xi_sms, and reading Configuration.php are your only reliable sources. Older bundles sometimes ignore unknown config keys silently — if your setting "does nothing," check the config tree first.+358401234567) and validate before sending; garbage numbers often return a provider error or, worse, succeed and cost money.%env()% or parameters.yml and keep the config file as structure only.\Exception at your sender boundary and translate to your own SmsException; some gateways throw on HTTP failure, others return a falsey value.services.yml with the same ID, and you can register a custom gateway class implementing the bundle's Gateway interface without forking. Check the interface signature in vendor/xi/sms — it is the most stable surface you have.-vvv and a Monolog handler on the SMS channel; if messages "disappear," verify the configured default gateway name matches an entry under gateways: exactly (a typo commonly resolves to a null/default gateway rather than throwing).send(to, body) call). Abstract it now and the eventual swap is mechanical.How can I help you explore Laravel packages today?