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

Remote Event Laravel Package

symfony/remote-event

Symfony RemoteEvent helps your app receive, validate, and handle remote events (like webhooks) in a consistent way. It provides tooling to parse payloads, verify signatures, map to event objects, and process them through Symfony’s event/HTTP workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel

  1. Install the Package

    composer require symfony/remote-event
    

    For Laravel-Symfony interop, also install:

    composer require symfony/dependency-injection symfony/http-client symfony/messenger
    
  2. Create a Basic Remote Event Class Define a DTO (Data Transfer Object) for your event payload:

    // app/Domain/Events/StripeWebhook.php
    namespace App\Domain\Events;
    
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    
    class StripeWebhook implements RemoteEventInterface
    {
        public function __construct(
            public string $eventType,
            public array $payload,
            public ?string $signature = null,
            public ?string $idempotencyKey = null
        ) {}
    }
    
  3. Configure a Transport (HTTP Example) Use Symfony’s HttpClient to fetch events (or integrate with Laravel’s HttpClient):

    // config/remote_event.php
    return [
        'transports' => [
            'stripe' => [
                'class' => \Symfony\Component\RemoteEvent\Transport\HttpTransport::class,
                'url' => 'https://api.stripe.com/events',
                'auth' => [
                    'method' => 'bearer',
                    'token' => env('STRIPE_SECRET_KEY'),
                ],
            ],
        ],
    ];
    
  4. First Use Case: Webhook Endpoint Create a Laravel controller to receive and process the event:

    // routes/web.php
    Route::post('/stripe-webhook', [StripeWebhookController::class, 'handle']);
    
    // app/Http/Controllers/StripeWebhookController.php
    use Symfony\Component\RemoteEvent\RemoteEvent;
    use Symfony\Component\RemoteEvent\Transport\HttpTransport;
    
    class StripeWebhookController extends Controller
    {
        public function handle(Request $request)
        {
            $transport = new HttpTransport(
                url: 'https://api.stripe.com/events',
                auth: ['method' => 'bearer', 'token' => env('STRIPE_SECRET_KEY')]
            );
    
            $remoteEvent = new RemoteEvent(
                payload: $request->getContent(),
                signature: $request->header('Stripe-Signature'),
                id: $request->header('Stripe-Idempotency-Key')
            );
    
            // Validate and dispatch
            $this->validateAndDispatch($remoteEvent);
        }
    
        protected function validateAndDispatch(RemoteEvent $event)
        {
            $validator = $this->container->get('validator');
            $errors = $validator->validate($event);
    
            if ($errors->count() > 0) {
                abort(400, 'Invalid event');
            }
    
            // Dispatch to Laravel's event system
            event(new \App\Events\StripeWebhookProcessed($event->getPayload()));
        }
    }
    

Implementation Patterns

1. Transport Integration

  • HTTP Transport: Use Symfony’s HttpClient or Laravel’s HttpClient to fetch events. Wrap it in a service:

    // app/Services/RemoteEventTransport.php
    use Symfony\Component\RemoteEvent\Transport\HttpTransport;
    use Illuminate\Support\Facades\Http;
    
    class RemoteEventTransport
    {
        public function fetch(string $url, array $headers = []): string
        {
            $response = Http::withHeaders($headers)->get($url);
            return $response->body();
        }
    
        public function createHttpTransport(array $config): HttpTransport
        {
            return new HttpTransport(
                url: $config['url'],
                auth: $config['auth'] ?? null,
                client: $this->createHttpClient($config)
            );
        }
    
        protected function createHttpClient(array $config): \Symfony\Contracts\HttpClient\HttpClientInterface
        {
            return \Symfony\Component\HttpClient\HttpClient::create([
                'auth_bearer' => $config['auth']['token'] ?? null,
            ]);
        }
    }
    
  • Queue Transport: For async processing, use Laravel’s queues with Symfony’s Messenger:

    // app/Providers/AppServiceProvider.php
    use Symfony\Component\Messenger\MessageBus;
    use Symfony\Component\Messenger\Transport\Serialization\Serializer;
    
    public function register()
    {
        $this->app->singleton(MessageBus::class, function ($app) {
            $bus = new MessageBus([
                new \Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransport(
                    $app['pestle.connection'],
                    new Serializer()
                ),
            ]);
            return $bus;
        });
    }
    

2. Event Validation

  • Use Symfony’s Validator to validate incoming events:

    // app/Domain/Events/StripeWebhook.php
    use Symfony\Component\Validator\Constraints as Assert;
    
    class StripeWebhook
    {
        #[Assert\NotBlank]
        public string $eventType;
    
        #[Assert\All({
            new Assert\Type('array'),
            new Assert\NotBlank()
        })]
        public array $payload;
    }
    
  • Integrate with Laravel’s validation:

    use Illuminate\Support\Facades\Validator;
    
    $validator = Validator::make($event->toArray(), [
        'eventType' => 'required|string',
        'payload' => 'required|array',
    ]);
    
    if ($validator->fails()) {
        abort(400, 'Validation failed');
    }
    

3. Middleware Pipeline

  • Add middleware to transform or log events:

    // app/Http/Middleware/LogRemoteEvents.php
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    use Psr\Log\LoggerInterface;
    
    class LogRemoteEvents
    {
        public function __construct(protected LoggerInterface $logger) {}
    
        public function __invoke(RemoteEventInterface $event): RemoteEventInterface
        {
            $this->logger->info('Remote event received', [
                'event_type' => $event->getType(),
                'payload' => $event->getPayload(),
            ]);
            return $event;
        }
    }
    
  • Register middleware in Laravel’s pipeline:

    // app/Providers/AppServiceProvider.php
    use Symfony\Component\RemoteEvent\RemoteEventBus;
    
    public function boot()
    {
        $bus = $this->app->make(RemoteEventBus::class);
        $bus->addMiddleware(new LogRemoteEvents($this->app->make(LoggerInterface::class)));
    }
    

4. Dispatching to Laravel Events

  • Bridge Symfony’s RemoteEvent to Laravel’s Event system:
    // app/Services/EventDispatcher.php
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    use Illuminate\Support\Facades\Event;
    
    class EventDispatcher
    {
        public function dispatch(RemoteEventInterface $event)
        {
            $laravelEvent = new \App\Events\RemoteEventProcessed(
                type: $event->getType(),
                payload: $event->getPayload()
            );
            Event::dispatch($laravelEvent);
        }
    }
    

5. Handling Retries

  • Use Laravel’s queue middleware for retries:
    // app/Console/Kernel.php
    protected function schedule(Schedule $schedule)
    {
        $schedule->job(new ProcessRemoteEventJob($event))->everyMinute()->withoutOverlapping();
    }
    

Gotchas and Tips

Pitfalls

  1. Service Container Conflicts

    • Symfony’s ContainerInterface expects a different structure than Laravel’s. Use a decorator pattern or service provider to bridge the gap:
      // app/Providers/SymfonyContainerProvider.php
      use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainer;
      
      class SymfonyContainerProvider extends ServiceProvider
      {
          public function register()
          {
              $this->app->singleton(SymfonyContainer::class, function () {
                  return new class($this->app) implements SymfonyContainer {
                      public function __construct(protected $laravelContainer) {}
      
                      public function get($id)
                      {
                          return $this->laravelContainer->make($id);
                      }
                  };
              });
          }
      }
      
  2. Event Serialization Mismatches

    • Laravel uses json_encode/json_decode by default, while Symfony may expect SerializerInterface. Normalize serialization:
      // app/Services/EventSerializer.php
      use Symfony\Component\Serializer\SerializerInterface;
      use Illuminate\Support\Facades\JSON;
      
      class EventSerializer
      {
          public function serialize($data): string
          {
              return JSON::encode($data);
          }
      
          public function deserialize(string $data, string $format, string $type): array
          {
              return JSON::decode($data, true);
          }
      }
      
  3. Idempotency Handling

    • Laravel’s queues don’t natively support idempotency. Use a database-backed solution:
      // app/Models/ProcessedEvent.php
      use Illuminate\Database\Eloquent\Model;
      
      class ProcessedEvent extends Model
      {
          protected $fillable = ['event_id', 'event
      
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata