The Observer Pattern Explained
Definition
The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Problem: Tight Coupling in Order Processing
namespace Vendor\Sales\Model;
class OrderProcessor
{
public function placeOrder(OrderInterface $order): void
{
$this->saveOrder($order);
$this->updateInventory($order); // Direct dependency
$this->sendEmail($order); // Direct dependency
$this->updateAnalytics($order); // Direct dependency
$this->notifyAdmin($order); // Direct dependency
// 5 direct dependencies — adding more = more coupling
}
}
Solution: Observer Pattern
// Subject: dispatches events
namespace Vendor\Sales\Event;
class OrderEventDispatcher
{
private array $listeners = [];
public function attach(string $event, callable $listener): void
{
$this->listeners[$event][] = $listener;
}
public function dispatch(string $event, mixed $data): void
{
foreach ($this->listeners[$event] ?? [] as $listener) {
$listener($data);
}
}
}
// Subject uses event dispatching
class OrderProcessor
{
public function __construct(
private OrderEventDispatcher $dispatcher
) {}
public function placeOrder(OrderInterface $order): void
{
$this->saveOrder($order);
$this->dispatcher->dispatch('order.placed', $order);
}
}
// Observers: independent, decoupled
$this->dispatcher->attach('order.placed', function ($order) {
$this->inventory->updateStock($order);
});
$this->dispatcher->attach('order.placed', function ($order) {
$this->emailSender->sendConfirmation($order);
});
$this->dispatcher->attach('order.placed', function ($order) {
$this->analytics->trackOrder($order);
});
// Adding new behavior = attaching new listener. Zero coupling.
The OrderProcessor doesn't know about inventory, email, or analytics. It just fires an event. Listeners subscribe independently.
Magento Events and Observers
How Magento Implements Events
Magento has a built-in event system using Magento\Framework\Event\Manager.
Dispatching Events
// In Magento core (simplified)
$eventManager = $this->eventManager;
$eventManager->dispatch('catalog_product_save_after', [
'product' => $product,
'object' => $product,
]);
$eventManager->dispatch('sales_order_place_after', [
'order' => $order,
]);
Defining Observers
<!-- app/code/Vendor/Module/etc/events.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<!-- Observe product save -->
<event name="catalog_product_save_after">
<observer name="vendor_product_sync"
instance="Vendor\Module\Observer\ProductSyncObserver"
disabled="false"/>
</event>
<!-- Observe order placement -->
<event name="sales_order_place_after">
<observer name="vendor_order_notification"
instance="Vendor\Module\Observer\OrderNotificationObserver"/>
</event>
</config>
Observer Implementation
namespace Vendor\Module\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer;
class ProductSyncObserver implements ObserverInterface
{
public function __construct(
private \Vendor\Sync\Api\ProductSyncInterface $syncService,
private \Psr\Log\LoggerInterface $logger
) {}
public function execute(Observer $observer): void
{
try {
$product = $observer->getEvent()->getProduct();
$this->syncService->sync($product);
} catch (\Exception $e) {
$this->logger->error('Product sync failed: ' . $e->getMessage());
}
}
}
Common Magento Events
| Event | When | Common Use |
|---|---|---|
catalog_product_save_after |
Product saved | Sync to external system |
sales_order_place_after |
Order placed | Send notifications |
customer_register_success |
Customer registered | Welcome email, CRM sync |
checkout_cart_update_items_after |
Cart updated | Recalculate totals |
admin_system_store_changed_websites |
Store config changed | Clear cache |
Observers vs Plugins: When to Use Which
Magento Plugins (Interceptors)
Plugins wrap specific methods on specific classes:
<type name="Magento\Catalog\Model\Product">
<plugin name="vendor_product_validate"
type="Vendor\Catalog\Plugin\ProductValidationPlugin"
sortOrder="10"/>
</type>
Plugins are method-level interception.
Magento Events/Observers
Events are system-wide notifications:
<event name="catalog_product_save_after">
<observer name="vendor_sync" instance="..."/>
</event>
Observers are event-level subscription.
Decision Guide
| Aspect | Plugin | Observer |
|---|---|---|
| Granularity | Specific method on specific class | Any event in the system |
| Timing | Before/after/around a method call | After an event is dispatched |
| Use when | Modifying behavior of one class | Reacting to system-wide events |
| Visibility | Only that class knows about it | Any module can observe |
| Testing | Easy to unit test | Requires event system |
// Plugin: Modify Product::getName() behavior
public function beforeGetName($subject)
{
// Runs before Product::getName()
}
// Observer: React to any product save
// catalog_product_save_after fires for ANY product save
// Your observer doesn't know or care which module saved it
Rule: If you need to modify one class's method → Plugin. If you need to react when something happens system-wide → Observer.
Quiz
1. What is the main benefit of the Observer pattern?
2. In Magento, when should you use a Plugin instead of an Observer?
3. How do you register an observer in Magento?
Flashcards
Question
What does the Observer pattern do?
Click to reveal answer
Answer
Notifies all dependents when a subject changes state, enabling loose coupling
Question
Magento Observer registration file?
Click to reveal answer
Answer
events.xml in the module's etc/ directory
Question
Plugin vs Observer?
Click to reveal answer
Answer
Plugin = method-level interception; Observer = system-wide event subscription
Question
How to dispatch a Magento event?
Click to reveal answer
Answer
$eventManager->dispatch('event_name', ['key' => $data]);
Revision Notes
Key Takeaways
- 1. Observer pattern: subject dispatches events, observers react independently
- 2. Magento events: system-wide notifications via Event\Manager::dispatch()
- 3. Observers registered in events.xml, implement ObserverInterface
- 4. Plugins = method-level interception; Observers = event-level subscription
- 5. Use Observer for cross-module communication; Plugin for method modification
Interview Tips
- • Give examples: catalog_product_save_after triggers external sync
- • Explain when Observer adds unnecessary coupling (tight coupling through events)
- • Discuss the trade-off: events are flexible but harder to trace than direct calls
Cheat Sheet
Observer Pattern:
Subject → dispatches event
Observer → reacts to event
Benefit → Loose coupling
Magento:
$this->eventManager->dispatch('event_name', ['data' => $data]);
events.xml:
<event name="event_name">
<observer name="unique_name" instance="Vendor\Module\Observer\Observer"/>
</event>
Plugin vs Observer:
Plugin → Modify specific method on specific class
Observer → React to system-wide event from any source