Beacon is an Event Management system built originally for use in the Phred Framework, but opened to the public to install in any codebase. It follows a strict PSR-14 (Event Dispatcher) implementation with an "Enterprise-First" architecture. # Features & Functionality (Mind Map) - Event Dispatcher (The "Engine") - Primary entry point: `$dispatcher->dispatch($event)` - Returns the modified/original event object (PSR-14) - **Contract Isolation**: Split into `BeaconContracts` (Interfaces) and `Beacon` (Implementation). - **Bridge Support**: `BeaconBridges` for third-party adapters (Symfony, Laravel). - **Middleware Pipeline**: Onion-style pipeline for pre/post dispatch logic. - **Resiliency**: Configurable error handling (Fail-fast vs. Continue/Log). - Event Listeners & Providers - **Listener Provider**: Separate PSR-14 component to resolve listeners for an event. - **Class-based Subscribers**: Implement `SubscriberInterface` for multiple events. - **Priority System**: Higher integer = higher priority (runs earlier). - **Wildcard Support**: Pattern matching (e.g., `App.User.*`) translated internally to cached regex for efficiency. - **Lazy Loading**: Listeners instantiated only when needed via PSR-11 container. - Event Objects & Context - **Plain Old PHP Objects (POPOs)**: Any object can be an event. - **Event Envelope**: Optional wrapper to carry immutable metadata/context via a `ContextMap`. - **Stoppable Events**: Implements `StoppableEventInterface` (PSR-14). - **Inheritance Resolution**: Automatically resolves listeners for parent classes and interfaces; includes a configuration toggle for high-performance interface skipping. - Discovery & Registration - **Attribute Discovery**: PHP 8.2 `#[AsEventListener]` for zero-config registration. - **Discovery Logic**: A `ListenerDiscovery` service scans directories (using PSR-4 mapping or explicit paths). - **Discovery Cache**: PSR-16 cache support for scanning and mapping attributes (eliminates runtime scanning). - **DI Integration**: Accept a PSR-11 container to resolve listener instances; discovery yields service IDs or class names for lazy instantiation. - **Manual Registration**: Fluent API for one-off listeners or closures (uses `addListener`). - Integration & Advanced Features - **Async Dispatching**: Offloaded via `QueueingDispatcher` decorator (in Bridges); serializes the `EventEnvelope`. - **PII & Logging**: Masking and sensitive data handling live strictly in Bridges or Middleware, keeping the engine core pure. - **Resiliency & Error Handling**: `continue` mode emits a `DispatchFailed` event containing the listener, exception, and original event payload for audit/retry. - **Enterprise Telemetry**: Trace execution timing and listener flow. - **Testing Helpers**: PHPUnit traits for easy event assertions. # Concepts: Unified Event Listening ## The Dispatcher API The primary way to trigger an event is through the `$dispatch()` method. ```php $dispatcher->dispatch($event); ``` ## Listener Registration We prefer structured class-based listeners, but support closures for lightweight tasks. - `addListener(string $event, callable $listener, int $priority = 0)` - `addSubscriber(SubscriberInterface $subscriber)` # API Examples (Drafts) ## Basic Dispatching ```php $dispatcher = new EventDispatcher($provider); $event = new UserRegistered($user); // "Enterprise" Dispatching $dispatcher->dispatch($event); ``` ## Middleware Example ```php class LoggingMiddleware implements DispatchMiddlewareInterface { public function handle(object $event, callable $next): object { $log->info("Dispatching: " . $event::class); return $next($event); } } ``` ## Class-based Subscriber (Unified) ```php class UserSubscriber implements SubscriberInterface { public static function getSubscribedEvents(): array { return [ UserRegistered::class => 'onUserRegistered', UserDeleted::class => ['onUserDeleted', 10], // with priority ]; } public function onUserRegistered(UserRegistered $event): void { /* ... */ } } ``` ## Attribute-based Discovery ```php #[AsEventListener(event: UserRegistered::class, priority: 10)] class SendWelcomeEmailListener { public function __invoke(UserRegistered $event): void { /* ... */ } } ``` ## Stoppable Events (with Convenience Trait) ```php class OrderEvent implements StoppableEventInterface { use CanStopPropagation; // Provides stopPropagation() and isPropagationStopped() } ``` ## Contextual Data (Envelope) ```php $envelope = new EventEnvelope($event, ['request_id' => 'abc-123']); $dispatcher->dispatch($envelope); ```