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

Vonage Notifier Laravel Package

symfony/vonage-notifier

Symfony Notifier bridge for Vonage, enabling SMS notifications via a simple DSN configuration. Set VONAGE_DSN with your Vonage key/secret and sender (“from”) to route notifications through Vonage.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require symfony/vonage-notifier
    
  2. Configure DSN in .env:

    VONAGE_DSN=vonage://KEY:SECRET@default?from=FROM
    

    Replace KEY, SECRET, and FROM with your Vonage credentials and sender ID.

  3. First use case: Send an SMS

    use Symfony\Component\Notifier\Notifier;
    use Symfony\Component\Notifier\Message\SmsMessage;
    
    $notifier = new Notifier([], [new VonageTransport($dsn)]);
    $notifier->send(new SmsMessage('Hello, world!', 'TO_NUMBER'));
    
  4. Verify in Vonage dashboard or check logs for delivery status.

Where to Look First

  • DSN Format: Vonage Notifier Documentation
  • Message Types: Supports SmsMessage, VoiceMessage, and EmailMessage (via Vonage’s unified API).
  • Webhook Handling: If using Vonage callbacks, review the security update for signature validation.

Implementation Patterns

Core Workflows

1. Transactional Notifications (SMS/Voice)

  • Pattern: Use Symfony’s Notifier or Messenger for async dispatch.
  • Example:
    // In a Laravel controller or Symfony command
    $notifier->send(new SmsMessage(
        'Your OTP is: ' . $otp,
        $user->phone
    ));
    

2. Multi-Channel Notifications

  • Pattern: Combine transports for fallback logic.
  • Example:
    $notifier = new Notifier([
        new VonageTransport($dsn, 'sms'),    // Primary
        new VonageTransport($dsn, 'voice'), // Fallback
    ]);
    

3. Scheduled Notifications

  • Pattern: Use Symfony Messenger with delay stamps.
  • Example:
    $message = new SmsMessage('Reminder: Meeting at 3 PM', 'TO_NUMBER');
    $message->delay(3600); // Send in 1 hour
    $bus->dispatch($message);
    

4. Webhook Handling (Critical)

  • Pattern: Validate signatures using hash_equals() (post-v8.1.0-BETA2).
  • Example:
    use Symfony\Component\Notifier\Bridge\Vonage\Webhook\VonageWebhookValidator;
    
    $validator = new VonageWebhookValidator('YOUR_SECRET');
    if ($validator->isValidSignature(
        $request->getContent(),
        $request->headers->get('X-Vonage-Signature')
    )) {
        // Process webhook (e.g., delivery receipt)
    }
    

Integration Tips

  • Laravel Adaptation: Create a custom notification channel by extending VonageChannel and integrating with Laravel’s Notification facade.

    use Symfony\Component\Notifier\Bridge\Vonage\VonageTransport;
    
    class VonageChannel extends Channel
    {
        public function __construct(VonageTransport $transport)
        {
            $this->transport = $transport;
        }
    }
    
  • Error Handling: Wrap notifications in try-catch blocks and log failures:

    try {
        $notifier->send($message);
    } catch (\Exception $e) {
        \Log::error('Vonage notification failed: ' . $e->getMessage());
    }
    
  • Testing: Use Symfony’s TransportFactoryTestCase (deprecated in v7.2+) or mock the VonageTransport:

    $transport = $this->createMock(VonageTransport::class);
    $transport->method('send')->willReturn(true);
    $notifier = new Notifier([], [$transport]);
    

Gotchas and Tips

Pitfalls

  1. Webhook Signature Validation (Critical Fix in v8.1.0-BETA2)

    • Issue: Older code using strcmp() or === for signature validation is vulnerable to timing attacks.
    • Fix: Replace with hash_equals():
      // Old (vulnerable)
      if (strcmp($expected, $received) === 0) { ... }
      
      // New (secure)
      if (hash_equals($expected, $received)) { ... }
      
    • Scope: Affects all webhook endpoints consuming Vonage callbacks (e.g., /webhooks/vonage).
  2. DSN Configuration Quirks

    • Issue: Missing from parameter in DSN causes InvalidArgumentException.
    • Fix: Ensure DSN includes ?from=YOUR_SENDER_ID:
      VONAGE_DSN=vonage://KEY:SECRET@default?from=YourApp
      
  3. Rate Limiting

    • Issue: Vonage enforces rate limits. Exceeding limits may silently fail.
    • Fix: Implement exponential backoff in retry logic:
      $retryDelay = 1000; // ms
      while ($attempts < 3) {
          try {
              $notifier->send($message);
              break;
          } catch (RateLimitException $e) {
              usleep($retryDelay);
              $retryDelay *= 2;
              $attempts++;
          }
      }
      
  4. Phone Number Formatting

    • Issue: Vonage requires E.164 format (e.g., +12125551234). Invalid formats cause InvalidPhoneNumberException.
    • Fix: Normalize numbers before sending:
      $phone = preg_replace('/[^0-9]/', '', $user->phone);
      if (strlen($phone) < 10) {
          $phone = '+1' . $phone; // Example for US numbers
      }
      
  5. Async Processing Gaps

    • Issue: Symfony Notifier is synchronous by default. Async dispatch requires Messenger.
    • Fix: Use Messenger with a queue transport:
      $bus = $container->get('messenger');
      $bus->dispatch($message); // Async
      

Debugging Tips

  • Enable Vonage Debug Mode: Set VONAGE_DEBUG=1 in .env to log API requests/responses.

    VONAGE_DSN=vonage://KEY:SECRET@default?from=YourApp&debug=1
    
  • Check Vonage Dashboard: Monitor Vonage Messages API for delivery stats, errors, or throttling.

  • Log Failed Notifications: Extend VonageTransport to log exceptions:

    class LoggingVonageTransport extends VonageTransport
    {
        public function send(MessageInterface $message): void
        {
            try {
                parent::send($message);
            } catch (\Exception $e) {
                \Log::error('Vonage send failed', [
                    'message' => $message->getContent(),
                    'to' => $message->getRecipients(),
                    'error' => $e->getMessage(),
                ]);
                throw $e;
            }
        }
    }
    

Extension Points

  1. Custom Message Templates

    • Override VonageTransport to preprocess messages:
      class CustomVonageTransport extends VonageTransport
      {
          public function send(MessageInterface $message): void
          {
              $content = $this->applyTemplate($message->getContent());
              $message = new SmsMessage($content, $message->getRecipients());
              parent::send($message);
          }
      
          private function applyTemplate(string $content): string
          {
              return str_replace('{app}', 'MyApp', $content);
          }
      }
      
  2. Webhook Extensions

    • Extend VonageWebhookValidator for custom signature logic:
      class CustomValidator extends VonageWebhookValidator
      {
          protected function generateSignature(array $data): string
          {
              // Custom signature generation
              return hash_hmac('sha256', $data['payload'], $this->secret);
          }
      }
      
  3. Fallback Transports

    • Chain transports for redundancy:
      $notifier = new Notifier([
          new VonageTransport($dsn), // Primary
          new EmailTransport(new GmailTransport($gmailDsn)), // Fallback
      ]);
      

Configuration Quirks

  • Environment Variables: Prefix Vonage DSN with NOTIFIER_VONAGE_DSN for Symfony’s Notifier component:
    NOTIFIER_VONAGE_DSN=vonage://KEY:SECRET@default?from=YourApp
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity