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

Platform Transport Bundle Laravel Package

digitalstate/platform-transport-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require digitalstate/platform-transport-bundle
    

    Ensure the bundle is registered in config/bundles.php:

    return [
        // ...
        DigitalState\TransportBundle\TransportBundle::class => ['all' => true],
    ];
    
  2. Database Setup Run migrations to create transport and profile tables:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    
  3. First Use Case: Sending an SMS Create a custom Transport class (e.g., TwilioTransport) implementing \Ds\Bundle\TransportBundle\Transport\Transport:

    namespace App\Transport\Sms;
    
    use Ds\Bundle\TransportBundle\Transport\Transport;
    use Ds\Bundle\TransportBundle\Model\Message;
    
    class TwilioTransport implements Transport {
        public function send(Message $message) {
            // Twilio logic here
        }
    }
    
  4. Register the Transport Define the transport in config/packages/transport.yaml:

    transports:
        twilio_sms:
            class: App\Transport\Sms\TwilioTransport
            profile: default_sms_profile
    
  5. Send a Message Inject the TransportManager and use it:

    use Ds\Bundle\TransportBundle\Manager\TransportManager;
    
    class MyService {
        public function __construct(private TransportManager $transportManager) {}
    
        public function sendWelcomeSms() {
            $message = new Message('+1234567890', 'Welcome!');
            $this->transportManager->send('twilio_sms', $message);
        }
    }
    

Implementation Patterns

Core Workflows

  1. Transport Creation

    • Extend the Transport interface to implement custom logic (e.g., email, SMS, push notifications).
    • Use dependency injection for external services (e.g., Twilio client, Mailer).
    • Example:
      class EmailTransport implements Transport {
          public function __construct(private \Swift_Mailer $mailer) {}
      
          public function send(Message $message) {
              $this->mailer->send(...);
          }
      }
      
  2. Profile Management

    • Profiles store configuration (e.g., API keys, sender IDs) for transports.
    • Create profiles via Doctrine or CLI:
      php bin/console make:entity Profile
      
    • Link profiles to transports in config/transport.yaml:
      transports:
          twilio_sms:
              profile: twilio_profile_id
      
  3. Message Handling

    • Use the Message class to standardize payloads:
      $message = new Message(
          recipient: 'recipient@example.com',
          body: 'Hello!',
          metadata: ['template' => 'welcome']
      );
      
    • Extend Message for custom fields if needed.
  4. Transport Manager

    • Use TransportManager to dynamically resolve transports:
      $this->transportManager->send('email', $message); // Resolves to EmailTransport
      
    • Override resolution logic by implementing TransportResolverInterface.
  5. Event-Driven Extensions

    • Listen to TransportEvent (e.g., PRE_SEND, POST_SEND) for logging, retries, or analytics:
      use Ds\Bundle\TransportBundle\Event\TransportEvent;
      
      $dispatcher->addListener(TransportEvent::PRE_SEND, function (TransportEvent $event) {
          // Pre-send logic (e.g., validation)
      });
      

Integration Tips

  1. Symfony Messenger Bridge Integrate with Symfony Messenger for async processing:

    # config/packages/messenger.yaml
    transports:
        async_transport:
            dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            retry_strategy:
                max_retries: 3
    

    Dispatch messages via Messenger:

    $this->messageBus->dispatch(new SendMessage($message));
    
  2. Doctrine ORM Use repositories to manage Transport and Profile entities:

    $profile = $this->profileRepository->find('default_sms_profile');
    $transport = $this->transportRepository->findOneBy(['profile' => $profile]);
    
  3. Configuration Validation Validate transport configurations in config/validator/transport.yaml:

    Ds\Bundle\TransportBundle\Entity\Transport:
        properties:
            class:
                - NotBlank
                - ClassExists
    
  4. Testing Mock transports in tests:

    $mockTransport = $this->createMock(Transport::class);
    $mockTransport->method('send')->willReturn(true);
    
    $this->transportManager->setTransport('test', $mockTransport);
    

Gotchas and Tips

Pitfalls

  1. Circular Dependencies

    • Avoid circular references between transports (e.g., Transport A calls Transport B, which calls Transport A).
    • Fix: Use the TransportManager to resolve transports by name, not directly instantiating them.
  2. Profile Misconfiguration

    • Ensure profiles are correctly linked to transports in the config. A missing profile will throw:
      Transport "twilio_sms" not found for profile "missing_profile".
      
    • Fix: Validate profiles exist before sending:
      if (!$this->transportManager->hasTransport('twilio_sms')) {
          throw new \RuntimeException('Transport not configured');
      }
      
  3. Message Serialization

    • Custom Message metadata must be serializable. Non-serializable objects (e.g., closures) will fail.
    • Fix: Use primitive types or JSON-serializable data:
      $message = new Message('recipient', 'body', ['data' => json_encode($complexObject)]);
      
  4. Transport Lifecycle

    • Transports are instantiated once per request by default. Stateful transports (e.g., caching connections) may cause issues.
    • Fix: Use stateless transports or clear state between requests.
  5. Doctrine Events

    • Overriding Transport or Profile lifecycle callbacks (e.g., prePersist) may conflict with bundle logic.
    • Fix: Extend entities instead of overriding events directly.

Debugging

  1. Enable Transport Logging Add to config/packages/monolog.yaml:

    handlers:
        transport:
            type: stream
            path: "%kernel.logs_dir%/transport.log"
            level: debug
            channels: ["transport"]
    

    Then log in your transport:

    $this->logger->debug('Sending message', ['message' => $message->getBody()]);
    
  2. Check Transport Resolution Debug transport resolution with:

    $transport = $this->transportManager->getTransport('twilio_sms');
    $this->logger->info('Transport class:', ['class' => get_class($transport)]);
    
  3. Validate Config Use Symfony’s config validator:

    php bin/console config:validate
    

Extension Points

  1. Custom Transport Resolver Implement TransportResolverInterface to override default resolution:

    class CustomResolver implements TransportResolverInterface {
        public function resolve(string $name): Transport {
            // Custom logic (e.g., load from DB dynamically)
        }
    }
    

    Register it in services.yaml:

    Ds\Bundle\TransportBundle\Manager\TransportManager:
        arguments:
            $resolver: '@custom_resolver'
    
  2. Transport Middleware Add middleware to transports (e.g., retry logic, analytics):

    class RetryMiddleware {
        public function __invoke(Transport $transport, Message $message) {
            try {
                $transport->send($message);
            } catch (\Exception $e) {
                // Retry logic
            }
        }
    }
    

    Wrap transports in TransportManager:

    services:
        App\Transport\RetryMiddleware:
            tags: [ds_transport.middleware]
    
  3. Custom Message Types Extend the Message class for domain-specific needs:

    class EmailMessage extends Message {
        public function __construct(
            string $to,
            string $subject,
            string $body,
            array $attachments = []
        ) {
            parent::__construct($to, $body);
            $this->subject = $subject;
            $this->attachments = $attachments;
        }
    }
    

    Update transports to handle the new type.

  4. Async Transport Queue Use Symfony Messenger with a queue transport:

    # config/packages/messenger.yaml
    transports:
        async:
            dsn: 'doctrine://default'
            retry_strategy:
                max_retries: 3
    

    Dispatch messages:

    $this->message
    
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.
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
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle