Skip to content
intermediate Phase 10 · More Design Patterns

Observer Pattern

Observer pattern for event-driven architecture, Magento events and observers, and when to use observers vs plugins

45m
0 problems
Topic Progress 0%

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?

Question 1 options

2. In Magento, when should you use a Plugin instead of an Observer?

Question 2 options

3. How do you register an observer in Magento?

Question 3 options

Flashcards

Question

What does the Observer pattern do?

Answer

Notifies all dependents when a subject changes state, enabling loose coupling

Question

Magento Observer registration file?

Answer

events.xml in the module's etc/ directory

Question

Plugin vs Observer?

Answer

Plugin = method-level interception; Observer = system-wide event subscription

Question

How to dispatch a Magento event?

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