Skip to main content
The EventsPlugin automatically discovers and registers event listeners from all enabled modules, similar to how Laravel’s own event discovery works.

Overview

This plugin scans each module’s src/Listeners directory for event listener classes and automatically registers them with Laravel’s event dispatcher. It respects your application’s event discovery configuration.

Source Location

InterNACHI\Modular\Plugins\EventsPlugin

Activation

The plugin uses the AfterResolving attribute to activate when the event dispatcher is resolved:
#[AfterResolving(Dispatcher::class, parameter: 'events')]
class EventsPlugin extends Plugin
This plugin only runs if event discovery is enabled in your application, either globally or through the package configuration.

How It Works

1. Discovery Check

The plugin first checks if event discovery should run:
protected function shouldDiscoverEvents(): bool
{
    return $this->config->get('app-modules.should_discover_events') 
        ?? $this->appIsConfiguredToDiscoverEvents();
}

protected function appIsConfiguredToDiscoverEvents(): bool
{
    return collect($this->app->getProviders(EventServiceProvider::class))
        ->filter(fn(EventServiceProvider $provider) => 
            $provider::class === EventServiceProvider::class
            || str_starts_with(get_class($provider), $this->app->getNamespace())
        )
        ->contains(fn(EventServiceProvider $provider) => 
            $provider->shouldDiscoverEvents()
        );
}

2. Discovery Phase

The discover() method scans listener directories:
public function discover(FinderFactory $finders): array
{
    if (! $this->shouldDiscoverEvents()) {
        return [];
    }
    
    return $finders
        ->listenerDirectoryFinder()
        ->withModuleInfo()
        ->reduce(fn(array $discovered, ModuleFileInfo $file) => array_merge_recursive(
            $discovered,
            DiscoverEvents::within($file->getPathname(), $file->module()->path('src'))
        ), []);
}

3. Registration Phase

The handle() method registers discovered listeners:
public function handle(Collection $data): void
{
    $data->each(function(array $listeners, string $event) {
        foreach (array_unique($listeners, SORT_REGULAR) as $listener) {
            $this->events->listen($event, $listener);
        }
    });
}
Duplicate listeners are automatically removed to prevent the same listener from being registered multiple times for the same event.

Configuration

You can control event discovery through the config/app-modules.php file:
return [
    'should_discover_events' => true, // or false to disable
];
If not set, the plugin will use your application’s EventServiceProvider configuration.

Expected Module Structure

For listeners to be discovered, they must be located in:
app-modules/
└── your-module/
    └── src/
        └── Listeners/
            └── SendWelcomeEmail.php

Example Listener

Event Class

namespace YourModule\Events;

class UserRegistered
{
    public function __construct(
        public User $user
    ) {}
}

Listener Class

namespace YourModule\Listeners;

use YourModule\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // Send welcome email to $event->user
    }
}

Type Hinting

Laravel’s event discovery works by inspecting the type hints on your listener’s handle() method. The plugin uses the same DiscoverEvents utility that Laravel uses internally.
public function handle(UserRegistered $event): void
{
    // The type hint tells Laravel this listener handles UserRegistered events
}

Queued Listeners

Listeners can implement ShouldQueue to be dispatched to the queue:
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // This will run on the queue
    }
}

Dependencies

  • Illuminate\Contracts\Events\Dispatcher - Event dispatcher
  • Illuminate\Contracts\Foundation\Application - Application instance
  • Illuminate\Contracts\Config\Repository - Configuration
  • InterNACHI\Modular\Support\DiscoverEvents - Event discovery utility

Build docs developers (and LLMs) love