Weave 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

Listeners Debug Laravel Package

egulias/listeners-debug

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps for Laravel Integration

  1. Install via Composer (for Symfony 2 compatibility):

    composer require egulias/listeners-debug
    

    Note: This will pull Symfony 2 dependencies, which may conflict with Laravel.

  2. Create a Laravel-Compatible Wrapper (since the package targets Symfony 2):

    // app/Services/LaravelListenerFetcher.php
    namespace App\Services;
    
    use Illuminate\Contracts\Events\Dispatcher;
    
    class LaravelListenerFetcher
    {
        public function __construct(private Dispatcher $events)
        {
        }
    
        public function fetchListeners(string $eventName = null): array
        {
            return $eventName
                ? $this->events->getListeners($eventName)
                : $this->events->getListeners();
        }
    }
    
  3. Register the Service in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(LaravelListenerFetcher::class, function ($app) {
            return new LaravelListenerFetcher($app['events']);
        });
    }
    
  4. First Use Case: Dump All Listeners

    use App\Services\LaravelListenerFetcher;
    
    $listeners = app(LaravelListenerFetcher::class)->fetchListeners();
    dd($listeners);
    

    Output: Array of all registered listeners with their closures/services.

  5. Filter by Event (Laravel-native equivalent):

    $userCreatedListeners = app(LaravelListenerFetcher::class)->fetchListeners('user.created');
    dd($userCreatedListeners);
    

Where to Look First

  • Laravel’s Native Tools: Start with app('events')->getListeners() before adapting this package.
  • Symfony-Specific Docs: If integrating with a Symfony 2 subsystem, refer to the original README for event_listener tag usage.
  • Debugbar Integration: Use spatie/laravel-debugbar for a GUI-based listener inspector.

Implementation Patterns

Usage Patterns in Laravel

1. Basic Listener Inspection

// Get all listeners for a specific event
$listeners = app(LaravelListenerFetcher::class)->fetchListeners('order.placed');

// Iterate with priorities (Laravel doesn't natively support priority, but you can add it)
foreach ($listeners as $priority => $handler) {
    echo "Priority: $priority, Handler: " . get_class($handler) . "\n";
}

2. Dynamic Debugging in Middleware

// app/Http/Middleware/DebugListeners.php
public function handle($request, Closure $next)
{
    if ($request->query('debug_listeners')) {
        $event = $request->query('event');
        dd(app(LaravelListenerFetcher::class)->fetchListeners($event));
    }
    return $next($request);
}

Usage: ?debug_listeners=1&event=user.created

3. Event Flow Visualization

// Generate a DOT graph for event dependencies
$graph = "digraph EventFlow {\n";
$listeners = app(LaravelListenerFetcher::class)->fetchListeners();

foreach ($listeners as $event => $handlers) {
    $graph .= "    \"$event\" -> {\n";
    foreach ($handlers as $handler) {
        $graph .= "        \"" . get_class($handler) . "\"\n";
    }
    $graph .= "    }\n";
}
$graph .= "}";

file_put_contents(storage_path('app/event_graph.dot'), $graph);

Render with: dot -Tpng event_graph.dot -o event_graph.png

4. CI/CD Integration

# Add to your deploy script to validate event listeners
php artisan tinker --execute="
    $listeners = app(LaravelListenerFetcher::class)->fetchListeners();
    if (empty($listeners['user.created'])) {
        throw new Exception('Critical event listener missing!');
    }
"

Workflows

Debugging Event Misfires

  1. Identify Missing Listeners:

    $expectedListeners = ['App\Listeners\SendWelcomeEmail'];
    $actualListeners = array_map(
        fn($handler) => is_string($handler) ? $handler : get_class($handler),
        app(LaravelListenerFetcher::class)->fetchListeners('user.created')
    );
    
    $missing = array_diff($expectedListeners, $actualListeners);
    if (!empty($missing)) {
        throw new \RuntimeException("Missing listeners: " . implode(', ', $missing));
    }
    
  2. Log Listener Execution (via a decorator):

    // app/Providers/EventServiceProvider.php
    public function boot()
    {
        $this->events->listen('*', function ($event) {
            $listeners = app(LaravelListenerFetcher::class)->fetchListeners(get_class($event));
            logger()->debug("Event triggered: " . get_class($event) . ". Listeners: " . json_encode($listeners));
        });
    }
    

Performance Profiling

// Measure listener execution time
$listeners = app(LaravelListenerFetcher::class)->fetchListeners('order.processed');
$times = [];

foreach ($listeners as $handler) {
    $start = microtime(true);
    $handler($event = new \stdClass()); // Dummy event
    $times[get_class($handler)] = microtime(true) - $start;
}

dd($times);

Integration Tips

1. Symfony 2 Bridge (Advanced)

If your Laravel app integrates with Symfony 2 (e.g., via a microkernel):

// app/Services/SymfonyListenerFetcher.php
use Egulias\ListenersDebug\ListenerFetcher;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class SymfonyListenerFetcher
{
    public function __construct(private ContainerBuilder $container)
    {
    }

    public function fetchListeners(bool $showPrivate = false): array
    {
        $symfonyFetcher = new ListenerFetcher($this->container);
        return $symfonyFetcher->fetchListeners($showPrivate);
    }
}

Register the ContainerBuilder via a Symfony 2 service provider.

2. Extending for Custom Metadata

// Add tags or descriptions to listeners
$listeners = app(LaravelListenerFetcher::class)->fetchListeners();
$enriched = [];

foreach ($listeners as $event => $handlers) {
    $enriched[$event] = [];
    foreach ($handlers as $handler) {
        $class = is_string($handler) ? $handler : get_class($handler);
        $enriched[$event][] = [
            'handler' => $class,
            'description' => $this->getListenerDescription($class),
        ];
    }
}

dd($enriched);

3. Command-Line Tool

// app/Console/Commands/DebugListeners.php
use Illuminate\Console\Command;

class DebugListeners extends Command
{
    protected $signature = 'debug:listeners {event?}';
    protected $description = 'List all event listeners';

    public function handle()
    {
        $listeners = app(LaravelListenerFetcher::class)->fetchListeners($this->argument('event'));
        $this->table(['Event', 'Handler'], collect($listeners)->mapWithKeys(function ($handlers, $event) {
            return [$event => array_map(fn($h) => is_string($h) ? $h : get_class($h), $handlers)];
        })->flatten());
    }
}

Usage: php artisan debug:listeners user.created


Gotchas and Tips

Pitfalls

  1. Symfony Dependency Conflicts:

    • Installing egulias/listeners-debug pulls in Symfony 2 components (e.g., symfony/dependency-injection:2.x), which may conflict with Laravel’s Symfony bridge or other packages.
    • Fix: Use a forked version or the Laravel wrapper above to avoid Symfony dependencies.
  2. Laravel vs. Symfony API Mismatches:

    • The package assumes event_listener tags in the DIC, but Laravel uses:
      • Closures (Event::listen()).
      • Service bindings ($events->listen()).
      • Class methods (handle()).
    • Fix: Normalize handlers to strings/classes in your wrapper:
      $handler = is_string($handler) ? $handler : (is_object($handler) ? get_class($handler) : 'closure');
      
  3. Private Listeners:

    • Laravel doesn’t have a direct equivalent to Symfony’s "private" listeners. The $showPrivate parameter in the original package will always return false in Laravel.
    • Fix: Ignore this parameter or treat all listeners as
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package