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:
- Code dispatches an event with a name and data array
- Event Manager looks up registered observers for that event
- Observers execute their
execute()method - 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 registrationinstance- Fully qualified class name of the observerdisabled- Set totrueto 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?
2. How do you access event data in an observer?
3. What is the transport object used for?
Flashcards
Question
What is the event naming convention in Magento?
Click to reveal answer
Answer
{area}_{entity}_{action}_{timing} (e.g., catalog_product_save_after)
Question
Where are observers registered?
Click to reveal answer
Answer
In events.xml files (global or area-specific etc/{area}/events.xml)
Question
What does the shared attribute do in events.xml?
Click to reveal answer
Answer
Reuses the same observer instance across all dispatches
Question
How do you pass data back from an observer?
Click to reveal answer
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