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

Event Laravel Package

sabre/event

Lightweight PHP 8.2+ library for event-driven development: EventEmitter, promises, an event loop, and coroutines. Used to build reactive, non-blocking apps and services. Full docs at sabre.io/event.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require sabre/event "^6.1"
    

    Ensure your project uses PHP 8.2+ (required for sabre/event v6.1).

  2. Basic Event Emitter:

    use Sabre\Event\Emitter;
    
    $emitter = new Emitter();
    $emitter->on('event.name', function ($arg) {
        echo "Event triggered with: " . $arg;
    });
    $emitter->emit('event.name', 'test');
    
  3. First Promise:

    use Sabre\Event\Promise;
    
    $promise = new Promise(function ($resolve) {
        $resolve('Done!');
    });
    $promise->then(function ($result) {
        echo $result; // Outputs: "Done!"
    });
    
  4. Run the Event Loop (for async operations):

    use Sabre\Event\EventLoop\EventLoop;
    
    $loop = new EventLoop();
    $loop->run();
    

Where to Look First

  • Official Documentation for API references, coroutines, and event loop usage.
  • Examples in the repo for real-world patterns (e.g., WebSocket servers, CLI tools).
  • Laravel Integration: Use sabre/event in Artisan commands, console kernels, or non-HTTP contexts (avoid HTTP routes to prevent blocking).

First Use Case: Async CLI Task

use Sabre\Event\Promise;
use Sabre\Event\EventLoop\EventLoop;

$loop = new EventLoop();
$promise = new Promise(function ($resolve) {
    sleep(2); // Simulate I/O
    $resolve('Task complete');
});

$promise->then(function ($result) {
    echo $result; // Runs after 2 seconds
});
$loop->run(); // Keep the loop alive

Implementation Patterns

Core Workflows

1. Event-Driven Architecture

  • Pattern: Decouple components using events.
  • Example:
    $emitter = new Emitter();
    $emitter->on('user.created', function ($user) {
        // Send welcome email
    });
    $emitter->on('user.created', function ($user) {
        // Log user creation
    });
    $emitter->emit('user.created', new User());
    
  • Laravel Tip: Use alongside Laravel’s Event system for hybrid patterns:
    $emitter->on('laravel.event', function ($event) {
        // Extend Laravel events with custom logic
    });
    

2. Promises for Async Operations

  • Pattern: Chain async operations with .then()/.otherwise().
  • Example:
    $promise = new Promise(function ($resolve) {
        $data = fetchFromApi();
        $resolve($data);
    });
    $promise->then(function ($data) {
        return processData($data);
    })->then(function ($result) {
        saveToDatabase($result);
    })->otherwise(function ($error) {
        logError($error);
    });
    
  • Laravel Tip: Use Promise\all() for parallel execution:
    $promises = [
        fetchUserData(),
        fetchOrderData(),
    ];
    Promise\all($promises)->then(function ($results) {
        // Both resolved
    });
    

3. Event Loop for Non-Blocking I/O

  • Pattern: Run async tasks without blocking the main thread.
  • Example (CLI tool):
    $loop = new EventLoop();
    $promise = new Promise(function ($resolve) {
        $loop->futureTick(function () use ($resolve) {
            $resolve('Async result');
        });
    });
    $promise->then(function ($result) {
        echo $result;
    });
    $loop->run();
    
  • Laravel Tip: Use in Artisan commands or queue workers (not HTTP routes).

4. Coroutines for Async Control Flow

  • Pattern: Use yield to pause/resume execution.
  • Example:
    $loop = new EventLoop();
    $coroutine = coroutine(function () {
        $result = yield new Promise(function ($resolve) {
            sleep(1);
            $resolve('Data');
        });
        echo $result; // Outputs after 1 second
    });
    $loop->run();
    
  • Laravel Tip: Ideal for complex async workflows in console apps.

Integration Tips

Laravel-Specific Patterns

  1. Console Kernel Integration:

    // app/Console/Kernel.php
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('async-task')->everyMinute();
    }
    

    Use sabre/event inside the command to run async logic.

  2. Service Providers:

    public function boot()
    {
        $this->app->make(Emitter::class)->on('app.started', function () {
            // Initialize async services
        });
    }
    
  3. Avoid HTTP Blocking:

    • Do: Use in Artisan commands, queue workers, or API consumers.
    • Don’t: Use in HTTP routes (blocks the request lifecycle).

Performance Optimization

  • Batch Events: Use Emitter::emit() with multiple listeners for efficiency.
  • Promise Reuse: Reuse Promise objects where possible to avoid overhead.
  • Event Loop Tuning: For high-load CLI tools, adjust EventLoop tick intervals.

Testing

  • Mock Emitters: Use Sabre\Event\Emitter in unit tests:
    $emitter = new Emitter();
    $emitter->on('test', $callback = fn() => 'triggered');
    $this->assertEquals('triggered', $emitter->emit('test'));
    
  • Promise Testing: Verify async flows with Promise::wait():
    $result = $promise->wait();
    $this->assertEquals('expected', $result);
    

Gotchas and Tips

Pitfalls

  1. Event Loop Blocks HTTP Requests

    • Issue: Running $loop->run() in a Laravel HTTP route will block the request indefinitely.
    • Fix: Use only in CLI/console contexts or queue workers.
  2. PHP 8.2+ Requirement

    • Issue: sabre/event v6.1+ requires PHP 8.2. Older versions (v6.0.x) support PHP 7.4–8.1.
    • Fix: Check composer.json constraints and upgrade PHP if needed.
  3. Promises Need the Event Loop

    • Issue: .then() callbacks won’t execute unless the EventLoop is running.
    • Fix: Always run $loop->run() for async Promise chains:
      $promise->then(...);
      $loop->run(); // Required!
      
  4. Wildcard Listeners Can Overlap

    • Issue: Emitter::on('*.event', ...) may match unintended events.
    • Fix: Use specific event names or prioritize listeners.
  5. Coroutines Require Generators

    • Issue: coroutine() expects a generator function (uses yield).
    • Fix: Ensure the passed function is a generator:
      $coroutine = coroutine(function () {
          yield new Promise(...); // Correct
      });
      

Debugging Tips

  1. Log Event Emissions:

    $emitter->on('*', function ($event, $args) {
        logger()->debug("Event $event triggered", ['args' => $args]);
    });
    
  2. Inspect Promise States:

    $promise->then(...)->otherwise(function ($error) {
        logger()->error("Promise rejected: " . $error->getMessage());
    });
    
  3. Event Loop Deadlocks:

    • Symptom: $loop->run() hangs indefinitely.
    • Fix: Ensure all Promise callbacks resolve/reject and no infinite loops exist.
  4. Priority Conflicts:

    • Issue: Listeners with the same priority may fire in unexpected orders.
    • Fix: Explicitly set priorities:
      $emitter->on('event', $callback, 10); // Higher priority
      

Configuration Quirks

  1. No Laravel Service Provider

    • Workaround: Bind Emitter manually in AppServiceProvider:
      $this->app->singleton(Emitter::class, function () {
          return new Emitter();
      });
      
  2. Event Loop in Queues

    • Tip: Use EventLoop in queue workers for async task coordination:
      // app/Console/
      
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