Skip to content
intermediate Phase 18 · Events, Plugins & DI

Magento 2 Events and Observers

Event system - dispatching events, creating observers, events.xml, and observer execution.

1h
0 problems
Topic Progress 0%

Magento Event System Architecture

Magento 2 uses an event-driven architecture where modules can dispatch events and other modules can observe and react to them without direct coupling.

Event flow:

  1. Code dispatches an event with a name and data array
  2. Event Manager looks up registered observers for that event
  3. Observers execute their execute() method
  4. Each observer receives the event data

Dispatching events:

// Basic dispatch
$this->eventManager->dispatch('my_custom_event', [
    'data' => $someObject,
    'result' => $result
]);

// With named keys for clarity
$this->eventManager->dispatch('catalog_product_save_after', [
    'product' => $product,
    'controller' => $this
]);

Event Manager class:

// vendor/magento/framework/Event/Manager.php
public function dispatch($name, array $data = [])
{
    $event = $this->Factory->create($name, $data);
    $this->ObserverCollection->dispatch($event);
    return $event;
}

Event naming conventions:

  • {area}_{entity}_{action}_{timing}
  • Examples: catalog_product_save_after, checkout_cart_add_product_complete, sales_order_place_before

Key benefits of events:

  • Loose coupling between modules
  • Multiple observers for one event
  • No code changes to the dispatching module
  • Easy to add functionality reactively

Creating Observers

Observer classes implement a single execute() method that receives the event object.

Observer class:

<?php
namespace Vendor\Module\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer;
use Psr\Log\LoggerInterface;

class ProductAfterSave implements ObserverInterface
{
    private $logger;
    private $emailService;
    
    public function __construct(
        LoggerInterface $logger,
        \Vendor\Module\Service\EmailService $emailService
    ) {
        $this->logger = $logger;
        $this->emailService = $emailService;
    }
    
    public function execute(Observer $observer)
    {
        $product = $observer->getEvent()->getProduct();
        $transportObject = $observer->getEvent()->getTransportObject();
        
        $this->logger->info('Product saved: ' . $product->getSku());
        
        // Send notification email
        $this->emailService->sendProductUpdateNotification($product);
        
        // Modify transport object to add custom data
        $transportObject->setData('custom_flag', true);
    }
}

Accessing event data:

public function execute(Observer $observer)
{
    // Method 1: Getter methods
    $product = $observer->getEvent()->getProduct();
    
    // Method 2: Array access
    $data = $observer->getEvent()->getData();
    $product = $data['product'];
    
    // Method 3: Direct data access
    $name = $observer->getEvent()->getName();
}

Using transport object to pass data:

// In the dispatching code
$transportObject = new \Magento\Framework\DataObject();
$this->eventManager->dispatch('my_event', [
    'transport_object' => $transportObject
]);
$value = $transportObject->getData('custom_value');

Transport objects allow observers to pass data back to the dispatching code without tight coupling.

Observer Registration via events.xml

Observers are registered in events.xml files, which can be area-specific.

Global events (all areas):

<!-- app/code/Vendor/Module/etc/events.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_after">
        <observer name="vendor_product_after_save"
                  instance="Vendor\Module\Observer\ProductAfterSave"
                  disabled="false"/>
    </event>
</config>

Area-specific events:

<!-- app/code/Vendor/Module/etc/frontend/events.xml -->
<config>
    <event name="controller_action_postdispatch_checkout_cart_add">
        <observer name="vendor_cart_add_tracking"
                  instance="Vendor\Module\Observer\CartAddTracking"/>
    </event>
</config>

Observer attributes:

  • name - Unique identifier for this observer registration
  • instance - Fully qualified class name of the observer
  • disabled - Set to true to disable without removing

Shared observers:

<event name="sales_order_save_after">
    <observer name="shared_observer"
              instance="Vendor\Module\Observer\SharedObserver"
              shared="true"/>
</event>

Observer sorting:

<event name="my_event">
    <observer name="first_observer"
              instance="Vendor\Module\Observer\First"
              sortOrder="10"/>
    <observer name="second_observer"
              instance="Vendor\Module\Observer\Second"
              sortOrder="20"/>
</event>

Multiple observers per event:

<event name="catalog_product_save_after">
    <observer name="email_notification" instance="...\EmailNotification"/>
    <observer name="inventory_update" instance="...\InventoryUpdate"/>
    <observer name="search_index" instance="...\SearchIndexUpdate"/>
</event>

Common Events and Best Practices

Magento dispatches hundreds of events throughout the request lifecycle. Knowing common events helps when building integrations.

Common events:

# Product events
catalog_product_save_before
Catalog_product_save_after
catalog_product_delete_before
Catalog_product_delete_after

# Category events
catalog_category_save_before
catalog_category_save_after

# Order events
sales_order_place_before
sales_order_place_after
sales_order_save_before
sales_order_save_after

# Customer events
customer_register_success
customer_login
Customer_logout

# Checkout events
checkout_cart_add_product_complete
checkout_onepage_controller_success_action
sales_quote_save_after

# Admin events
admin_session_user_login_success
admin_session_user_login_failed

When to use events vs plugins:

Scenario Use Events Use Plugins
Decoupled integration ✓
Modify return value ✓
Cross-module communication ✓
Before/after method logic ✓
Third-party integration ✓

Best practices:

  • Dispatch events with descriptive names
  • Always pass relevant objects in event data
  • Don't modify core code to add events (use plugins)
  • Keep observers focused on single responsibility
  • Use disabled="true" for conditional observer loading
  • Name observers uniquely across all modules

Quiz

1. What method must an observer class implement?

Question 1 options

2. How do you access event data in an observer?

Question 2 options

3. What is the transport object used for?

Question 3 options

Flashcards

Question

What is the event naming convention in Magento?

Answer

{area}_{entity}_{action}_{timing} (e.g., catalog_product_save_after)

Question

Where are observers registered?

Answer

In events.xml files (global or area-specific etc/{area}/events.xml)

Question

What does the shared attribute do in events.xml?

Answer

Reuses the same observer instance across all dispatches

Question

How do you pass data back from an observer?

Answer

Using a transport object (Magento\Framework\DataObject)

Revision Notes

Key Takeaways

  • 1. Events enable loose coupling between modules
  • 2. Observers implement execute(Observer $observer)
  • 3. Events.xml registers observers with instance and name
  • 4. Area-specific events.xml for area-scoped observers
  • 5. Transport objects pass data from observer to dispatcher
  • 6. Events are best for cross-module communication

Interview Tips

  • Explain the event/observer pattern and when to use it
  • List common Magento events for product, order, and customer
  • Compare events vs plugins - when to use each
  • Describe how to create a custom event and observer
  • Discuss observer sorting and shared instances

Cheat Sheet

Events & Observers Cheat Sheet

Dispatch:

$this->eventManager->dispatch('event_name', ['key' => $value]);

Observer:

class MyObserver implements ObserverInterface
{
    public function execute(Observer $observer)
    {
        $data = $observer->getEvent()->getData();
    }
}

Registration (events.xml):

<event name="catalog_product_save_after">
    <observer name="unique_name"
              instance="Vendor\Module\Observer\MyObserver"/>
</event>

Common Events:

  • catalog_product_save_after
  • sales_order_place_after
  • customer_register_success
  • checkout_cart_add_product_complete