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
    
  2. First Use Case: Webhook Handling Define a remote event class (e.g., StripePaymentEvent):

    // app/Events/StripePaymentEvent.php
    namespace App\Events;
    
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    use Symfony\Component\RemoteEvent\RemoteEvent;
    
    class StripePaymentEvent extends RemoteEvent implements RemoteEventInterface
    {
        public function __construct(
            private array $payload,
            private string $signature,
            private string $expectedSignature
        ) {}
    
        public function getPayload(): array
        {
            return $this->payload;
        }
    
        public function getSignature(): string
        {
            return $this->signature;
        }
    
        public function getExpectedSignature(): string
        {
            return $this->expectedSignature;
        }
    }
    
  3. Create a Transport Handler (HTTP-based):

    // app/Services/RemoteEventTransport.php
    use Symfony\Component\RemoteEvent\Transport\RemoteEventTransportInterface;
    use Symfony\Component\HttpClient\HttpClient;
    use Symfony\Component\RemoteEvent\RemoteEvent;
    
    class HttpRemoteEventTransport implements RemoteEventTransportInterface
    {
        public function receive(): RemoteEvent
        {
            $client = HttpClient::create();
            $response = $client->request('GET', 'https://example.com/webhook');
    
            return new RemoteEvent(
                json_decode($response->getContent(), true),
                $response->getHeaders()['x-signature'][0] ?? null
            );
        }
    }
    
  4. Register in Laravel:

    // config/app.php (providers)
    Symfony\Component\RemoteEvent\RemoteEventBundle::class,
    
    // config/services.php
    'remote_event.transport' => App\Services\HttpRemoteEventTransport::class,
    
  5. Handle the Event (Laravel-style):

    // routes/web.php
    use App\Events\StripePaymentEvent;
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    
    Route::post('/webhook', function () {
        $event = app()->make(RemoteEventInterface::class);
        event(new StripePaymentEvent(
            $event->getPayload(),
            $event->getSignature(),
            'expected_signature_here'
        ));
    });
    

Implementation Patterns

1. Transport Layer Abstraction

  • Pattern: Decouple transport (HTTP, AMQP, etc.) from business logic using interfaces.
  • Example:
    // app/Interfaces/RemoteEventTransportInterface.php
    interface RemoteEventTransportInterface
    {
        public function receive(): RemoteEventInterface;
        public function send(RemoteEventInterface $event): void;
    }
    
  • Laravel Integration: Use Laravel’s bind() in a service provider to resolve transports dynamically:
    $this->app->bind(RemoteEventTransportInterface::class, function ($app) {
        return new HttpRemoteEventTransport(
            $app->make(HttpClient::class)
        );
    });
    

2. Event Validation

  • Pattern: Validate remote events using Symfony’s Validator (compatible with Laravel’s Validator).
  • Example:
    use Symfony\Component\Validator\Constraints as Assert;
    use Symfony\Component\Validator\Validation;
    
    $validator = Validation::createValidator();
    $errors = $validator->validate($event, [
        new Assert\NotBlank(['message' => 'Payload cannot be empty']),
        new Assert\Type(['type' => 'array', 'message' => 'Payload must be an array']),
    ]);
    

3. Middleware Pipeline

  • Pattern: Use PSR-15 middleware to transform/validate events before processing.
  • Example:
    // app/Middleware/LogRemoteEventMiddleware.php
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Server\MiddlewareInterface;
    use Psr\Http\Server\RequestHandlerInterface;
    
    class LogRemoteEventMiddleware implements MiddlewareInterface
    {
        public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        {
            \Log::info('Remote event received', ['payload' => $request->getParsedBody()]);
            return $handler->handle($request);
        }
    }
    
  • Laravel Integration: Register middleware in app/Http/Kernel.php or use Symfony’s MiddlewareStack.

4. Messenger Integration (Async Processing)

  • Pattern: Dispatch remote events to Symfony’s Messenger (compatible with Laravel’s queues).
  • Example:
    // config/packages/messenger.yaml (Symfony)
    framework:
        messenger:
            transports:
                async: '%env(MESSENGER_TRANSPORT_DSN)%'
            routing:
                'App\Events\StripePaymentEvent': async
    
  • Laravel Bridge: Use symfony/messenger with Laravel’s queue system:
    $this->app->bind(\Symfony\Component\Messenger\MessageBusInterface::class, function ($app) {
        $bus = new MessageBus([
            new AsyncTransport($app->make(Queue::class)),
        ]);
        return $bus;
    });
    

5. Event Retry Logic

  • Pattern: Leverage Symfony’s RetryStrategy for failed event processing.
  • Example:
    use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
    use Symfony\Component\Messenger\Transport\RetryStrategy\RetryStrategyInterface;
    
    $transport = new AsyncTransport($queue, new Serializer(), new RetryStrategy());
    

6. Laravel Event Bridge

  • Pattern: Convert RemoteEvent to Laravel’s Event for seamless integration.
  • Example:
    // app/Services/RemoteEventDispatcher.php
    use Symfony\Component\RemoteEvent\RemoteEventInterface;
    use Illuminate\Support\Facades\Event;
    
    class RemoteEventDispatcher
    {
        public function dispatch(RemoteEventInterface $event): void
        {
            $laravelEvent = new LaravelRemoteEvent($event);
            Event::dispatch($laravelEvent);
        }
    }
    

Gotchas and Tips

1. Laravel-Symfony Container Conflicts

  • Gotcha: Symfony’s ContainerInterface clashes with Laravel’s Container.
  • Fix: Use a decorator pattern or Laravel service provider to abstract dependencies:
    // app/Providers/RemoteEventServiceProvider.php
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    class RemoteEventServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(ContainerInterface::class, function () {
                return new LaravelContainerAdapter($this->app);
            });
        }
    }
    

2. Event Serialization Mismatches

  • Gotcha: Laravel’s json_encode/json_decode may not match Symfony’s Serializer.
  • Tip: Use Symfony’s Serializer for consistency:
    $serializer = new Serializer([new JsonEncoder()], [new JsonDecoder()]);
    $payload = $serializer->decode($event->getContent(), 'json');
    

3. Signature Verification Pitfalls

  • Gotcha: Manual signature checks can fail due to timing or payload ordering.
  • Tip: Use Symfony’s SignatureValidator:
    use Symfony\Component\RemoteEvent\Validator\SignatureValidator;
    
    $validator = new SignatureValidator('secret_key');
    if (!$validator->isValid($event->getSignature(), $event->getPayload())) {
        throw new \RuntimeException('Invalid signature');
    }
    

4. Async Processing Quirks

  • Gotcha: Laravel’s queues may not handle Symfony’s Message objects directly.
  • Fix: Serialize messages before dispatching:
    $serializer = new Serializer();
    $message = $serializer->serialize($event, 'json');
    Queue::push(new ProcessRemoteEventJob($message));
    

5. Middleware Ordering

  • Gotcha: PSR-15 middleware runs in reverse order of registration.
  • Tip: Register middleware in app/Http/Kernel.php or use Symfony’s MiddlewareStack:
    $middlewareStack = new MiddlewareStack();
    $middlewareStack->push(new LogRemoteEventMiddleware());
    $middlewareStack->push(new ValidateRemoteEventMiddleware());
    

6. Debugging Remote Events

  • Tip: Log raw payloads and signatures for debugging:
    \Log::debug('Remote event payload', [
        'payload' => $event->getPayload(),
        'signature' => $event->getSignature(),
        'headers' => $event->getHeaders(),
    ]);
    

**7

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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope