Core Concepts
Understanding the extension point architecture
What Are Extension Points?
Extension points are well-defined places in your code where other parts of the application (or third-party packages) can hook in and extend functionality.
Think of them as:
- Events with guaranteed contracts
- Hooks with type safety
- Plugin points with IDE support
Extension Points vs Events
| Feature | Laravel Events | Extension Points |
|---|---|---|
| Type Safety | String-based | Class-based |
| IDE Support | Limited | Full autocompletion |
| Return Values | Via event object | Via strategies |
| Interruption | Manual | Built-in support |
| Circuit Breaker | No | Yes |
| Async | Via listeners | Built-in attributes |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────────────┤
│ │
│ dispatch(UserCreated) │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ ExtensionDispatcher │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ HandlerRegistry │───▶│ Circuit Breaker │ │
│ │ (Priority sorted) │ │ (Failure protection) │ │
│ └──────────┬──────────┘ └─────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Handlers (by priority) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │Handler 1│ │Handler 2│ │Handler 3│ │Handler 4│ │ │
│ │ │(p: 10) │ │(p: 20) │ │(p: 50) │ │(p: 100) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Key Components
1. Extension Point
A class that represents a hookable moment:
class OrderPlaced implements ExtensionPointContract
{
public function __construct(
public readonly Order $order,
public readonly User $customer
) {}
}
2. Handler
A class that responds to an extension point:
class SendOrderConfirmation implements ExtensionHandlerContract
{
public function handle(ExtensionPointContract $extension): void
{
// React to the extension point
}
}
3. Registry
Maintains the mapping of extension points to handlers:
Extensions::register(OrderPlaced::class, SendOrderConfirmation::class);
Extensions::register(OrderPlaced::class, UpdateInventory::class);
Extensions::register(OrderPlaced::class, NotifyWarehouse::class);
4. Dispatcher
Executes handlers when an extension point is dispatched:
Extensions::dispatch(new OrderPlaced($order, $customer));
Handler Priorities
Handlers execute in priority order (lower = earlier):
| Priority Range | Use Case | Examples |
|---|---|---|
| 0-49 | Critical | Security checks, validation |
| 50-99 | High | Cache invalidation |
| 100-149 | Normal | Business logic |
| 150-199 | Low | Notifications |
| 200+ | Very Low | Analytics, logging |
Extensions::register(OrderPlaced::class, ValidateOrder::class, priority: 10);
Extensions::register(OrderPlaced::class, ProcessPayment::class, priority: 50);
Extensions::register(OrderPlaced::class, SendEmail::class, priority: 150);
Extensions::register(OrderPlaced::class, TrackAnalytics::class, priority: 200);
Interruptible Extension Points
Some extension points can be interrupted (vetoed):
class CanDeleteUser implements ExtensionPointContract, InterruptibleContract
{
public function __construct(public readonly User $user) {}
}
Handlers can prevent the action:
class PreventAdminDeletion implements ExtensionHandlerContract
{
public function handle(ExtensionPointContract $extension): bool
{
if ($extension->user->isAdmin()) {
return false; // Veto!
}
return true; // Allow
}
}
Dispatch and check:
$canDelete = Extensions::dispatchInterruptible(new CanDeleteUser($user));
if (!$canDelete) {
return back()->with('error', 'Cannot delete this user');
}
Contracts Overview
| Contract | Purpose |
|---|---|
ExtensionPointContract |
Marker for extension points |
ExtensionHandlerContract |
Handler must implement handle() |
InterruptibleContract |
Extension can be vetoed |
AsyncHandlerContract |
Handler runs asynchronously |
PipeableContract |
Supports pipeline transformation |