Extension Points

Hook into module lifecycle events

Overview

Extension points allow you to hook into module lifecycle events. They integrate with the laravel-extensions package for a type-safe hook system.

Available Extension Points

Before Hooks (Can Veto)

These fire before an action and can prevent it:

Extension Point Fires When
BeforeModuleInstall Before installing a module
BeforeModuleEnable Before enabling a module
BeforeModuleDisable Before disabling a module
BeforeModuleUninstall Before removing a module
BeforeModuleMigrate Before running migrations
BeforeModuleSeed Before running seeders

After Hooks

These fire after an action completes:

Extension Point Fires When
ModuleInstalled After module is installed
ModuleEnabled After module is enabled
ModuleDisabled After module is disabled
ModuleUninstalled After module is removed
ModuleMigrated After migrations run
ModuleSeeded After seeders run

Listening to Extension Points

Register a Handler

use Esegments\LaravelExtensions\Facades\Extensions;
use Esegments\ModularArchitecture\Extensions\Points\ModuleEnabled;

Extensions::register(
    ModuleEnabled::class,
    ClearCacheOnModuleChange::class
);

Handler Implementation

use Esegments\LaravelExtensions\Contracts\ExtensionHandlerContract;
use Esegments\ModularArchitecture\Extensions\Points\ModuleEnabled;

class ClearCacheOnModuleChange implements ExtensionHandlerContract
{
    public function handle(ModuleEnabled $extension): void
    {
        $module = $extension->module;
        
        Cache::tags(['modules', $module->getName()])->flush();
        
        Log::info("Cache cleared for module: {$module->getName()}");
    }
}

Vetoing Actions

Before hooks can prevent the action by returning false:

use Esegments\ModularArchitecture\Extensions\Points\BeforeModuleDisable;

class PreventCoreDisable implements ExtensionHandlerContract
{
    public function handle(BeforeModuleDisable $extension): bool
    {
        if ($extension->module->getName() === 'Core') {
            Log::warning('Attempted to disable Core module');
            return false; // Veto!
        }
        
        return true; // Allow
    }
}

Register with interruptible dispatch:

Extensions::register(BeforeModuleDisable::class, PreventCoreDisable::class);

// The system uses dispatchInterruptible() internally

Extension Point Properties

All extension points provide:

$extension->module;      // Module instance
$extension->moduleName;  // Module name string
$extension->source;      // Source info (CLI, API, etc.)
$extension->version;     // Module version
$extension->path;        // Module path

Common Use Cases

1. Clear Caches

class ClearCachesHandler implements ExtensionHandlerContract
{
    public function handle(ModuleEnabled|ModuleDisabled $extension): void
    {
        Artisan::call('cache:clear');
        Artisan::call('config:clear');
        Artisan::call('route:clear');
        Artisan::call('view:clear');
    }
}

Extensions::register(ModuleEnabled::class, ClearCachesHandler::class);
Extensions::register(ModuleDisabled::class, ClearCachesHandler::class);

2. Audit Logging

class AuditModuleChanges implements ExtensionHandlerContract
{
    public function handle(ExtensionPointContract $extension): void
    {
        AuditLog::create([
            'action' => class_basename($extension),
            'module' => $extension->moduleName,
            'user_id' => auth()->id(),
            'timestamp' => now(),
        ]);
    }
}

// Register for all module events
$events = [
    ModuleInstalled::class,
    ModuleEnabled::class,
    ModuleDisabled::class,
    ModuleUninstalled::class,
];

foreach ($events as $event) {
    Extensions::register($event, AuditModuleChanges::class);
}

3. Notify Administrators

class NotifyOnModuleChange implements ExtensionHandlerContract
{
    public function handle(ExtensionPointContract $extension): void
    {
        $admins = User::where('is_admin', true)->get();
        
        Notification::send($admins, new ModuleChangedNotification(
            action: class_basename($extension),
            module: $extension->moduleName
        ));
    }
}

4. Pre-Migration Backup

class BackupBeforeMigration implements ExtensionHandlerContract
{
    public function handle(BeforeModuleMigrate $extension): void
    {
        Artisan::call('backup:run', [
            '--only-db' => true,
            '--disable-notifications' => true,
        ]);
    }
}

5. Validation Before Enable

class ValidateLicense implements ExtensionHandlerContract
{
    public function handle(BeforeModuleEnable $extension): bool
    {
        $module = $extension->module;
        
        if ($this->requiresLicense($module) && !$this->hasValidLicense($module)) {
            Log::error("Module {$module->getName()} requires a valid license");
            return false;
        }
        
        return true;
    }
}

Extension Points Diagram

┌─────────────────────────────────────────────────────────────┐
│                      Install Flow                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   BeforeModuleInstall ─┬─▶ [handlers] ──▶ Download/Extract │
│                        └─▶ (can veto)                       │
│                                   │                         │
│                                   ▼                         │
│                        ModuleInstalled ──▶ [handlers]       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      Enable Flow                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   BeforeModuleEnable ─┬─▶ [handlers] ──▶ Update State      │
│                       └─▶ (can veto)                        │
│                                   │                         │
│                                   ▼                         │
│                        ModuleEnabled ──▶ [handlers]         │
│                                                             │
└─────────────────────────────────────────────────────────────┘