Weave Code
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 Bundle Laravel Package

adapik/sms-bundle

Symfony bundle for sending and scheduling SMS via multiple providers (MessageBird, SMS.ru, SMS Aero, SMS Discount, SMS Center). Configure multiple providers, pick one via ProviderManager, create Sms objects with optional delivery time, and send.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require yamilovs/sms-bundle ^1.0
    
  2. Enable the Bundle in config/bundles.php:
    return [
        // ...
        Yamilovs\Bundle\SmsBundle\SmsBundle::class => ['all' => true],
    ];
    
  3. Configure Providers in config/packages/sms.yaml:
    sms:
        providers:
            message_bird:
                api_key: "%env(MESSAGE_BIRD_API_KEY)%"
                # Other provider-specific configs
    
  4. First Use Case: Send an SMS via a controller:
    use Yamilovs\Bundle\SmsBundle\Service\ProviderManager;
    use Yamilovs\Bundle\SmsBundle\Sms\Sms;
    
    public function sendSms(ProviderManager $providerManager)
    {
        $sms = new Sms('+1234567890', 'Hello from Laravel!');
        $provider = $providerManager->getProvider('message_bird');
        $provider->send($sms);
    }
    

Where to Look First

  • Provider Docs: Check src/Resources/docs/providers/ for provider-specific guides (e.g., message_bird.md).
  • Service Container: Use ProviderManager to dynamically switch providers.
  • Environment Variables: Store API keys in .env (e.g., MESSAGE_BIRD_API_KEY).

Implementation Patterns

Core Workflow

  1. Define SMS Message:
    $sms = new Sms(
        recipient: '+1234567890',
        body: 'Your OTP is 123456',
        sender?: 'YourApp', // Optional
        scheduledAt?: new \DateTime('+1 hour') // Optional
    );
    
  2. Select Provider:
    $provider = $providerManager->getProvider('sms_ru');
    
  3. Send SMS:
    $provider->send($sms);
    
    • For scheduled SMS, pass a DateTime object to scheduledAt.

Integration Tips

  • Dependency Injection: Inject ProviderManager into services/controllers to avoid tight coupling.
    public function __construct(private ProviderManager $providerManager) {}
    
  • Provider Fallback: Use a loop to retry with alternative providers if the first fails:
    $providers = ['message_bird', 'sms_ru'];
    foreach ($providers as $providerName) {
        try {
            $provider = $providerManager->getProvider($providerName);
            $provider->send($sms);
            break;
        } catch (\Exception $e) {
            // Log or handle failure
        }
    }
    
  • Event Listeners: Extend functionality by listening to sms.sent or sms.failed events (if supported; check bundle docs).
  • Testing: Mock ProviderManager and providers in unit tests:
    $this->mockProviderManager->shouldReceive('getProvider')->andReturnSelf();
    $this->mockProvider->shouldReceive('send')->once();
    

Advanced Patterns

  • Dynamic Provider Selection: Use a config or database to store the active provider name, then fetch it dynamically:
    $activeProvider = $this->configService->get('sms.active_provider');
    $provider = $providerManager->getProvider($activeProvider);
    
  • Bulk SMS: Loop through recipients and send individually (no built-in bulk support; implement as needed):
    foreach ($recipients as $phone) {
        $provider->send(new Sms($phone, $message));
    }
    
  • Template-Based SMS: Store SMS templates in the database and hydrate them with dynamic data:
    $template = $this->templateRepository->find('welcome');
    $sms = new Sms($phone, $template->render(['name' => 'John']));
    

Gotchas and Tips

Pitfalls

  1. Provider-Specific Quirks:

    • Message Bird: Requires originator (sender ID) to be alphanumeric and pre-approved.
    • SMS Ru: Uses from instead of sender in the API payload.
    • SMS Center: Supports Unicode but may charge extra for long messages.
    • Fix: Always check src/Resources/docs/providers/ for provider-specific constraints.
  2. Rate Limiting:

    • Providers like SMS Ru may throttle requests. Implement exponential backoff in retries:
      try {
          $provider->send($sms);
      } catch (RateLimitException $e) {
          sleep(2 ** $attempt); // Exponential backoff
          retry();
      }
      
  3. Timezone Issues:

    • Scheduled SMS uses the server’s timezone. Explicitly set scheduledAt with a timezone-aware DateTime:
      $scheduledAt = new \DateTime('+1 hour', new \DateTimeZone('UTC'));
      $sms = new Sms($phone, $message, scheduledAt: $scheduledAt);
      
  4. Missing Error Handling:

    • The bundle may not throw exceptions for all failure cases (e.g., invalid phone numbers). Wrap calls in try-catch:
      try {
          $provider->send($sms);
      } catch (\Exception $e) {
          $this->logger->error('SMS failed', ['error' => $e->getMessage()]);
          // Re-throw or handle gracefully
      }
      
  5. Configuration Overrides:

    • Provider configs in sms.yaml are merged. Override specific values per environment:
      # config/packages/sms.yaml (dev)
      sms:
          providers:
              message_bird:
                  api_key: "%env(MESSAGE_BIRD_API_KEY_DEV)%"
      

Debugging Tips

  1. Enable Debug Mode: Set debug: true in sms.yaml to log provider responses:

    sms:
        debug: true
    
    • Logs will appear in var/log/dev.log.
  2. Validate Phone Numbers: Use a library like libphonenumber to validate formats before sending:

    use libphonenumber\PhoneNumberUtil;
    use libphonenumber\PhoneNumberFormat;
    
    $phoneUtil = PhoneNumberUtil::getInstance();
    $phone = $phoneUtil->parse($rawPhone, 'RU'); // Country code
    $validPhone = $phoneUtil->format($phone, PhoneNumberFormat::E164);
    
  3. Check Provider Status:

    • Some providers (e.g., SMS Ru) have status APIs. Poll them to verify delivery:
      $status = $provider->getStatus($sms->getId());
      

Extension Points

  1. Custom Providers: Implement the ProviderInterface to add support for new providers:

    use Yamilovs\Bundle\SmsBundle\Provider\ProviderInterface;
    
    class CustomProvider implements ProviderInterface {
        public function send(Sms $sms): void {
            // Custom logic (e.g., HTTP request to your SMS gateway)
        }
    }
    

    Register it in services.yaml:

    services:
        Yamilovs\Bundle\SmsBundle\Provider\CustomProvider:
            tags: ['sms.provider']
    
  2. Middleware for SMS: Add preprocessing/validation middleware by extending the Sms class or using a decorator pattern:

    class ValidatedSms extends Sms {
        public function __construct(string $recipient, string $body) {
            if (!preg_match('/^\+[0-9]{10,15}$/', $recipient)) {
                throw new \InvalidArgumentException('Invalid phone number');
            }
            parent::__construct($recipient, $body);
        }
    }
    
  3. Database Logging: Extend the bundle to log sent SMS to a database table:

    // After $provider->send($sms)
    $this->smsRepository->create([
        'phone' => $sms->getRecipient(),
        'message' => $sms->getBody(),
        'status' => 'sent',
        'provider' => $providerName,
    ]);
    
  4. Webhook Integration: Listen for provider webhooks (e.g., delivery reports) by setting up a Symfony event subscriber:

    use Symfony\Component\HttpKernel\Event\RequestEvent;
    
    class SmsWebhookSubscriber {
        public function onKernelRequest(RequestEvent $event) {
            if ($event->getRequest()->getPathInfo() === '/sms/webhook') {
                $this->handleWebhook($event->getRequest());
            }
        }
    }
    
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours