kch/smsapi-bundle
KCH SMSAPI Bundle integrates SMSAPI messaging into PHP applications, providing configuration and service wiring for sending SMS messages. It helps developers add text-message delivery to web apps and workflows with a lightweight, straightforward package.
This is a Symfony 2 bundle, not a Laravel package — there is no service provider, no facade, no config/*.php, and it will not be auto-discovered. Before you write a single line of integration code, accept the framing: in a Laravel app you will almost certainly consume the underlying smsapi/smsapi-php-client library directly and treat the bundle only as a reference implementation for how to wire credentials and a client instance.
Where to look first (in the bundle source):
DependencyInjection/Configuration.php — the canonical list of config keys (username/password vs. OAuth token, sender name, test-mode flag, formatting options). Copy these names into your own config/smsapi.php.DependencyInjection/KchSmsapiExtension.php — shows how the client is constructed and which setters are called in what order.Resources/config/services.xml — the service id and constructor arguments; this is the "recipe" you translate into a Laravel singleton.KchSmsapiBundle.php — usually 5 lines, confirms it is a plain Bundle subclass.Minimal Laravel setup (the realistic path):
composer require smsapi/smsapi-php-client
// config/smsapi.php
return [
'username' => env('SMSAPI_USERNAME'),
'password' => env('SMSAPI_PASSWORD'),
'sender' => env('SMSAPI_SENDER', 'MyApp'),
'test' => env('SMSAPI_TEST', false),
];
// app/Providers/SmsApiServiceProvider.php
public function register(): void
{
$this->app->singleton(\SMSApi\Client\SMSApiClient::class, function ($app) {
$cfg = $app['config']['smsapi'];
// Legacy client shape: set credentials fluently
return (new \SMSApi\Client\SMSApiClient($cfg['username'], $cfg['password']));
});
}
First use case: transactional OTP for password reset or phone verification. It is the lowest-risk, highest-value entry point — one recipient, one short message, easy to verify end-to-end against the provider's test mode before you touch bulk or marketing sends.
1. Bind the client as a singleton, resolve by interface. The bundle registers one configured service; mirror that. If you later swap providers (Twilio, Vonage), depend on your own SmsSender contract, not the vendor class.
interface SmsSender {
public function send(string $to, string $text, ?string $from = null): string;
}
2. Wrap sending in a queued job. SMS APIs are network-bound and rate-limited; never block a request on them.
final class SendSms implements ShouldQueue
{
use Queueable, SerializesModels;
public int $tries = 3;
public int $backoff = 30;
public function __construct(
public string $to,
public string $text,
public ?string $from = null,
) {}
public function handle(SmsSender $sms): void
{
$sms->send($this->to, $this->text, $this->from);
}
}
3. Use a Laravel Notification channel for anything user-facing. This keeps templates, locale, and recipient resolution out of your domain code.
// app/Notifications/PhoneVerified.php
public function via($notifiable) { return [SmsChannel::class]; }
public function toSms($notifiable): string
{
return __('Your code is :code', ['code' => $this->code]);
}
4. Normalize recipients at the boundary. The Polish SMSAPI service expects E.164-ish numbers. Store numbers with a country code and validate with libphonenumber-style rules before they reach the client; the bundle does not do this for you.
5. Bulk sends: chunk and track. The client exposes single-recipient and bulk endpoints. For campaign-style sends, chunk at ~100–500 per request, persist a sms_log row (to, provider_id, status, segments, cost), and reconcile asynchronously via delivery-report callbacks.
6. Configuration through env, secrets through the container. The bundle hardcodes config into Symfony's parameter bag; in Laravel put credentials in .env (or a secrets manager) and keep the shape in config/smsapi.php so config:cache works.
7. Delivery reports need an endpoint. SMSAPI is callback-oriented — expose a signed, idempotent webhook route (POST /webhooks/smsapi) and verify the request before updating your sms_log.
composer require kch/smsapi-bundle in a Laravel app. It pulls Symfony 2-era constraints on symfony/http-kernel and symfony/dependency-injection, which will collide with the Symfony 5/6/7 components Laravel depends on. Even if resolution succeeds, the bundle does nothing at runtime in Laravel — bundles are only registered by Symfony's Kernel. You get a transitive dependency headache for zero functionality.ąćęłńóśźż switch from GSM-7 (160 chars) to UCS-2 (70 chars) and multiply your cost. Normalize diacritics for internal/technical messages, or budget for two segments and log segments returned by the API.from value silently falls back to a shared number or fails outright depending on your contract. Confirm the sender name in the SMSAPI panel before debugging your code.isError()-style check rather than throwing. Always inspect the result explicitly and log the raw payload — HTTP 200 with an error body is common.retry() with exponential backoff, and only retry on transport errors or 5xx — retrying an SMS on a 4xx can double-bill.Bus::batch() of 10k jobs will hit it and return 429s. Throttle the job middleware (RateLimited) against your contract's limit.Configuration.php into a Laravel config file verbatim (same key names), then write a single ServiceProvider that instantiates the client with those keys. That is 40 lines of glue and removes the bundle entirely.How can I help you explore Laravel packages today?