Laravel Event System Showcase
Discover real-world examples and use cases of Laravel Event System in action. See how different applications leverage dynamic event management to build flexible, maintainable, and scalable event-driven architectures.
Understanding Event System Components
Laravel Event System provides powerful features for managing events dynamically:
- Dynamic Event Registration: Register and manage event-listener bindings at runtime without code changes
- Domain Event Architecture: Implement domain events with stable keys and rich metadata
- Event Bus & Registry: Dispatch events by stable keys instead of hard-coding class names
- Database-Driven Management: Store event configurations in the database for UI/API management
- Priority Control: Control listener execution order with priority values
- Status Management: Enable or disable listeners without removing them
E-Commerce Plugin System
Modular Plugin Architecture
Enable plugins to register their own events dynamically
Overview
E-commerce platforms often need to support third-party plugins that extend functionality. These plugins may need to hook into core application events like user registration, order completion, or product updates. Laravel Event System enables plugins to register their own event listeners dynamically, allowing them to integrate seamlessly without modifying core application code.
Plugin Capabilities
- Register event listeners on installation
- Unregister listeners on uninstallation
- Control listener priority
- Enable/disable without uninstalling
- Multiple plugins for same event
- Isolated plugin configurations
Business Benefits
- Extensible architecture
- No core code modifications
- Easy plugin management
- Runtime configuration
- Plugin marketplace support
- Version compatibility
Implementation Example
namespace App\Plugins\EmailNotification;
use JobMetric\EventSystem\Facades\EventSystem;
use App\Events\UserRegistered;
use App\Events\OrderCompleted;
use App\Events\ProductCreated;
class EmailNotificationPlugin
{
private array $registeredEvents = [];
public function install(): void
{
$this->registeredEvents = [
'plugin.email.user.registered',
'plugin.email.order.completed',
'plugin.email.product.created',
];
addEventSystem(
'plugin.email.user.registered',
UserRegistered::class,
EmailNotificationPlugin\Listeners\SendWelcomeEmail::class,
priority: 50,
description: 'Email Plugin: Send welcome email to new users'
);
addEventSystem(
'plugin.email.order.completed',
OrderCompleted::class,
EmailNotificationPlugin\Listeners\SendOrderConfirmation::class,
priority: 30,
description: 'Email Plugin: Send order confirmation email'
);
addEventSystem(
'plugin.email.product.created',
ProductCreated::class,
EmailNotificationPlugin\Listeners\NotifyAdminsNewProduct::class,
priority: 20,
description: 'Email Plugin: Notify admins of new products'
);
}
public function uninstall(): void
{
foreach ($this->registeredEvents as $eventName) {
try {
deleteEventSystem($eventName);
} catch (\Exception $e) {
Log::warning("Failed to unregister event: {$eventName}", [
'error' => $e->getMessage()
]);
}
}
}
public function enable(): void
{
foreach ($this->registeredEvents as $eventName) {
$event = EventSystem::query()
->where('name', $eventName)
->first();
if ($event && !$event->status) {
EventSystem::toggleStatus($event->id);
}
}
}
public function disable(): void
{
foreach ($this->registeredEvents as $eventName) {
$event = EventSystem::query()
->where('name', $eventName)
->first();
if ($event && $event->status) {
EventSystem::toggleStatus($event->id);
}
}
}
}
Domain-Driven Design Architecture
Domain Event System
Implement DDD patterns with stable event keys and rich metadata
Overview
Domain-Driven Design emphasizes the importance of domain events—events that represent something significant that happened in your domain. Laravel Event System provides a robust foundation for implementing DDD patterns with domain events that have stable keys, rich metadata, and consistent structure. This enables you to build decoupled, maintainable systems where events are dispatched by stable keys rather than hard-coded class names.
Domain Events
- Stable event keys
- Rich metadata (title, description, icon, tags)
- Consistent structure
- Registry-based lookup
- Key-based dispatching
- UI integration support
Architecture Benefits
- Decoupled components
- Testable event system
- Maintainable codebase
- Event discovery
- Documentation generation
- Workflow automation
Implementation Example
namespace App\Domain\Product\Events;
use JobMetric\EventSystem\Contracts\DomainEvent;
use JobMetric\EventSystem\Support\DomainEventDefinition;
class ProductCreated implements DomainEvent
{
public function __construct(
public int $productId,
public string $name,
public float $price,
public int $categoryId,
public int $createdBy
) {}
public static function key(): string
{
return 'product.created';
}
public static function definition(): DomainEventDefinition
{
return new DomainEventDefinition(
self::key(),
'product::events.group',
'product::events.created.title',
'product::events.created.description',
'fas fa-box',
['product', 'inventory', 'catalog']
);
}
}
class ProductPriceUpdated implements DomainEvent
{
public function __construct(
public int $productId,
public float $oldPrice,
public float $newPrice,
public int $updatedBy
) {}
public static function key(): string
{
return 'product.price.updated';
}
public static function definition(): DomainEventDefinition
{
return new DomainEventDefinition(
self::key(),
'product::events.group',
'product::events.price_updated.title',
'product::events.price_updated.description',
'fas fa-dollar-sign',
['product', 'pricing', 'inventory']
);
}
}
class ProductStockDepleted implements DomainEvent
{
public function __construct(
public int $productId,
public int $remainingStock
) {}
public static function key(): string
{
return 'product.stock.depleted';
}
public static function definition(): DomainEventDefinition
{
return new DomainEventDefinition(
self::key(),
'product::events.group',
'product::events.stock_depleted.title',
'product::events.stock_depleted.description',
'fas fa-exclamation-triangle',
['product', 'inventory', 'alert']
);
}
}
Register Domain Events:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use JobMetric\EventSystem\Support\EventRegistry;
use App\Domain\Product\Events\ProductCreated;
use App\Domain\Product\Events\ProductPriceUpdated;
use App\Domain\Product\Events\ProductStockDepleted;
class EventSystemServiceProvider extends ServiceProvider
{
public function boot(EventRegistry $registry): void
{
$registry->register(ProductCreated::class);
$registry->register(ProductPriceUpdated::class);
$registry->register(ProductStockDepleted::class);
}
}
Dispatch Events:
namespace App\Services;
use JobMetric\EventSystem\Facades\EventBus;
use App\Domain\Product\Events\ProductCreated;
use App\Domain\Product\Events\ProductPriceUpdated;
class ProductService
{
public function createProduct(array $data): Product
{
$product = Product::create($data);
eventKey('product.created',
$product->id,
$product->name,
$product->price,
$product->category_id,
auth()->id()
);
return $product;
}
public function updatePrice(Product $product, float $newPrice): void
{
$oldPrice = $product->price;
$product->update(['price' => $newPrice]);
eventKey('product.price.updated',
$product->id,
$oldPrice,
$newPrice,
auth()->id()
);
}
}
Admin Panel for Event Management
Event Management Dashboard
Build admin interfaces for managing events through UI
Overview
Non-technical administrators often need to manage event configurations without code changes. Laravel Event System enables you to build powerful admin interfaces where administrators can view all registered events, enable or disable listeners, change priorities, and even register new event bindings—all through a user-friendly interface.
Admin Features
- List all event bindings
- Filter and search events
- Enable/disable listeners
- Change execution priority
- Register new bindings
- View event metadata
Business Benefits
- No deployment needed
- Faster configuration changes
- Reduced developer dependency
- Real-time event management
- Audit trail of changes
- Better control and visibility
Implementation Example
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use JobMetric\EventSystem\Facades\EventSystem;
use JobMetric\EventSystem\Http\Resources\EventSystemResource;
use Illuminate\Http\Request;
class EventSystemController extends Controller
{
public function index(Request $request)
{
$events = EventSystem::paginate(
filter: $request->only(['status', 'event', 'listener']),
page_limit: $request->get('per_page', 15)
);
return view('admin.events.index', [
'events' => EventSystemResource::collection($events)
]);
}
public function create()
{
$availableEvents = $this->getAvailableEvents();
$availableListeners = $this->getAvailableListeners();
return view('admin.events.create', compact('availableEvents', 'availableListeners'));
}
public function store(Request $request)
{
$response = EventSystem::store($request->validate([
'name' => 'required|string|max:255|unique:events,name',
'description' => 'nullable|string',
'event' => 'required|string',
'listener' => 'required|string',
'priority' => 'nullable|integer',
'status' => 'boolean',
]));
if ($response->isSuccess()) {
return redirect()->route('admin.events.index')
->with('success', $response->getMessage());
}
return back()->withErrors($response->getErrors());
}
public function toggleStatus(int $id)
{
$response = EventSystem::toggleStatus($id);
return response()->json([
'success' => $response->isSuccess(),
'message' => $response->getMessage(),
'data' => EventSystemResource::make($response->getData())
]);
}
public function destroy(string $name)
{
$response = EventSystem::delete($name);
if ($response->isSuccess()) {
return redirect()->route('admin.events.index')
->with('success', $response->getMessage());
}
return back()->withErrors($response->getErrors());
}
private function getAvailableEvents(): array
{
$registry = app(\JobMetric\EventSystem\Support\EventRegistry::class);
$definitions = $registry->allDefinitions();
return collect($definitions)->map(function ($definition, $key) {
return [
'key' => $key,
'class' => $registry->forKey($key),
'title' => trans($definition->title),
'description' => trans($definition->description),
'icon' => $definition->icon,
'tags' => $definition->tags ?? [],
];
})->values()->toArray();
}
private function getAvailableListeners(): array
{
return [
'App\Listeners\SendWelcomeEmail',
'App\Listeners\SendOrderConfirmation',
'App\Listeners\TrackUserRegistration',
'App\Listeners\UpdateInventory',
'App\Listeners\SendNotification',
];
}
}
Multi-Tenant Event Configuration
Tenant-Specific Event Handlers
Configure different event handlers for different tenants
Overview
Multi-tenant SaaS applications often need different event handling logic for different tenants. For example, one tenant might want email notifications while another prefers SMS. Laravel Event System allows you to register tenant-specific event handlers dynamically, enabling each tenant to configure their own event behavior without affecting others.
Tenant Features
- Isolated event configurations
- Tenant-specific listeners
- Custom notification channels
- Different priority orders
- Feature-based enabling
- Tenant event isolation
Business Benefits
- Customized experiences
- Flexible configurations
- No code changes needed
- Tenant self-service
- Scalable architecture
- Better tenant satisfaction
Implementation Example
namespace App\Services;
use JobMetric\EventSystem\Facades\EventSystem;
use App\Models\Tenant;
class TenantEventConfigurationService
{
public function configureTenantEvents(Tenant $tenant): void
{
$tenantId = $tenant->id;
$preferences = $tenant->event_preferences ?? [];
if ($preferences['email_enabled'] ?? false) {
addEventSystem(
"tenant.{$tenantId}.user.created.email",
App\Events\UserCreated::class,
App\Listeners\Tenant\SendEmailNotification::class,
priority: 50,
description: "Tenant {$tenant->name}: Email notification"
);
}
if ($preferences['sms_enabled'] ?? false) {
addEventSystem(
"tenant.{$tenantId}.user.created.sms",
App\Events\UserCreated::class,
App\Listeners\Tenant\SendSMSNotification::class,
priority: 40,
description: "Tenant {$tenant->name}: SMS notification"
);
}
if ($preferences['slack_enabled'] ?? false) {
addEventSystem(
"tenant.{$tenantId}.user.created.slack",
App\Events\UserCreated::class,
App\Listeners\Tenant\SendSlackNotification::class,
priority: 30,
description: "Tenant {$tenant->name}: Slack notification"
);
}
if ($preferences['webhook_enabled'] ?? false) {
addEventSystem(
"tenant.{$tenantId}.user.created.webhook",
App\Events\UserCreated::class,
App\Listeners\Tenant\SendWebhookNotification::class,
priority: 20,
description: "Tenant {$tenant->name}: Webhook notification"
);
}
}
public function updateTenantEvents(Tenant $tenant, array $preferences): void
{
$this->removeTenantEvents($tenant);
$tenant->update(['event_preferences' => $preferences]);
$this->configureTenantEvents($tenant);
}
public function removeTenantEvents(Tenant $tenant): void
{
$tenantId = $tenant->id;
$events = EventSystem::query()
->where('name', 'like', "tenant.{$tenantId}.%")
->get();
foreach ($events as $event) {
EventSystem::delete($event->name);
}
}
}
A/B Testing Event Handlers
Event Handler Testing
Test different event handlers dynamically without code changes
Overview
A/B testing different event handlers allows you to experiment with different notification strategies, email templates, or processing logic. Laravel Event System makes it easy to register multiple handlers for the same event, enable or disable them dynamically, and measure their performance—all without deploying new code.
Testing Capabilities
- Multiple handlers per event
- Enable/disable handlers
- Priority-based execution
- Performance tracking
- Gradual rollout
- Easy rollback
Business Benefits
- Data-driven decisions
- Risk-free experimentation
- Faster iteration
- Better user experience
- Optimized processes
- Competitive advantage
Implementation Example
namespace App\Services;
use JobMetric\EventSystem\Facades\EventSystem;
use Illuminate\Support\Facades\Cache;
class ABTestingService
{
public function setupWelcomeEmailTest(): void
{
$variantA = 'welcome.email.variant.a';
$variantB = 'welcome.email.variant.b';
addEventSystem(
$variantA,
App\Events\UserRegistered::class,
App\Listeners\WelcomeEmail\VariantA\SendWelcomeEmail::class,
priority: 50,
description: 'A/B Test: Welcome Email Variant A (Simple)',
status: true
);
addEventSystem(
$variantB,
App\Events\UserRegistered::class,
App\Listeners\WelcomeEmail\VariantB\SendWelcomeEmail::class,
priority: 50,
description: 'A/B Test: Welcome Email Variant B (Rich)',
status: false
);
}
public function enableVariant(string $variantName, int $percentage = 50): void
{
$event = EventSystem::query()
->where('name', $variantName)
->first();
if (!$event) {
return;
}
if ($percentage === 100) {
EventSystem::toggleStatus($event->id);
} else {
Cache::put("ab_test.{$variantName}.percentage", $percentage, now()->addDays(7));
}
}
public function shouldUseVariant(string $variantName, int $userId): bool
{
$percentage = Cache::get("ab_test.{$variantName}.percentage", 0);
if ($percentage === 0) {
return false;
}
return ($userId % 100) < $percentage;
}
public function trackVariantPerformance(string $variantName, string $metric, float $value): void
{
$key = "ab_test.{$variantName}.{$metric}";
$current = Cache::get($key, ['count' => 0, 'total' => 0]);
Cache::put($key, [
'count' => $current['count'] + 1,
'total' => $current['total'] + $value,
'average' => ($current['total'] + $value) / ($current['count'] + 1),
], now()->addDays(30));
}
}
Usage in Listener:
namespace App\Listeners\WelcomeEmail\VariantA;
use App\Services\ABTestingService;
use App\Events\UserRegistered;
class SendWelcomeEmail
{
public function handle(UserRegistered $event): void
{
$abTesting = app(ABTestingService::class);
if (!$abTesting->shouldUseVariant('welcome.email.variant.a', $event->userId)) {
return;
}
Mail::to($event->user->email)->send(new WelcomeEmailVariantA($event->user));
$abTesting->trackVariantPerformance('welcome.email.variant.a', 'sent', 1);
}
}
Workflow Automation System
Event-Driven Workflows
Build automation systems triggered by domain events
Overview
Workflow automation systems need to respond to various domain events and trigger automated actions. Laravel Event System provides a perfect foundation for building such systems, where administrators can configure workflows by selecting domain events and defining actions to execute when those events occur. The rich metadata in domain events makes it easy to build user-friendly workflow builders.
Workflow Features
- Event selection UI
- Action configuration
- Condition-based triggers
- Multi-step workflows
- Workflow templates
- Execution logging
Business Benefits
- Automated processes
- Reduced manual work
- Consistent execution
- Error reduction
- Scalable automation
- Business agility
Implementation Example
namespace App\Services;
use JobMetric\EventSystem\Support\EventRegistry;
use JobMetric\EventSystem\Facades\EventBus;
class WorkflowAutomationService
{
public function createWorkflow(array $config): void
{
$workflowId = $config['id'];
$triggerEvent = $config['trigger_event'];
$actions = $config['actions'];
foreach ($actions as $index => $action) {
$listenerClass = $this->getListenerClassForAction($action['type']);
addEventSystem(
"workflow.{$workflowId}.action.{$index}",
$this->getEventClass($triggerEvent),
$listenerClass,
priority: 100 - $index,
description: "Workflow {$workflowId}: {$action['name']}",
status: $action['enabled'] ?? true
);
}
}
public function getAvailableEvents(): array
{
$registry = app(EventRegistry::class);
$definitions = $registry->allDefinitions();
return collect($definitions)->map(function ($definition, $key) use ($registry) {
return [
'key' => $key,
'class' => $registry->forKey($key),
'title' => trans($definition->title),
'description' => trans($definition->description),
'icon' => $definition->icon,
'tags' => $definition->tags ?? [],
'group' => trans($definition->group),
];
})->groupBy('group')->toArray();
}
private function getEventClass(string $eventKey): string
{
$registry = app(EventRegistry::class);
return $registry->forKey($eventKey) ?? throw new \Exception("Event not found: {$eventKey}");
}
private function getListenerClassForAction(string $actionType): string
{
return match($actionType) {
'send_email' => App\Listeners\Workflow\SendEmailAction::class,
'send_sms' => App\Listeners\Workflow\SendSMSAction::class,
'create_task' => App\Listeners\Workflow\CreateTaskAction::class,
'update_status' => App\Listeners\Workflow\UpdateStatusAction::class,
'webhook' => App\Listeners\Workflow\WebhookAction::class,
default => throw new \Exception("Unknown action type: {$actionType}"),
};
}
}