Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Events and observers

An event is a "something happened" message that code sends at a certain moment: a product was opened, an order was placed, a customer logged in. An observer is a class that is subscribed to an event and runs when it happens. This is how a module reacts to core actions without interfering with core code.

Where the files live

A subscription is described in an events.xml file, and observer classes go into the Observer folder. Both files are created by hand.

app/code/Acme/Hello/
├── Observer/
│   └── LogProductView.php      new file
└── etc/
    ├── module.xml
    └── frontend/
        ├── events.xml          new file
        └── routes.xml

A file in etc/frontend applies only to the storefront, in etc/adminhtml only to the admin panel, and etc/events.xml applies everywhere.

Subscribing

When a customer opens a product page, the core dispatches the catalog_controller_product_view event. Let's subscribe to it:

<?xml version="1.0"?>
<!-- app/code/Acme/Hello/etc/frontend/events.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_controller_product_view">
        <observer name="acme_hello_log_product_view" instance="Acme\Hello\Observer\LogProductView"/>
    </event>
</config>

The name attribute of observer is any unique name, instance is the observer class.

The observer

// app/code/Acme/Hello/Observer/LogProductView.php
namespace Acme\Hello\Observer;
 
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;
 
class LogProductView implements ObserverInterface
{
    public function __construct(private LoggerInterface $logger) {}
 
    public function execute(Observer $observer): void
    {
        $product = $observer->getEvent()->getData('product');
 
        $this->logger->info('Product viewed: ' . $product->getSku());
    }
}

Run bin/magento cache:clean and open any product page: a line with its SKU appears in the var/log/system.log file. Data travels with the event — here it is the product under the product key.

Common events

EventWhen it happensData
catalog_controller_product_viewA product page is openedproduct
catalog_product_save_afterA product is savedproduct
checkout_cart_product_add_afterA product is added to the cartquote_item, product
sales_order_place_afterAn order is placedorder
customer_loginA customer logs incustomer

The easiest way to find other core events is to search the vendor/magento folder for dispatch(.

Your own event

A module can dispatch its own events so that other modules can react to them. Ask for Magento\Framework\Event\ManagerInterface in the constructor:

// app/code/Acme/Hello/Model/Greeter.php
use Magento\Framework\Event\ManagerInterface;
 
public function __construct(private ManagerInterface $eventManager) {}
 
public function greet(string $name): string
{
    $this->eventManager->dispatch('acme_hello_greeted', ['name' => $name]);
 
    return 'Hello, ' . $name . '!';
}

An observer subscribed to acme_hello_greeted gets the name through $observer->getEvent()->getData('name'). By convention an event name starts with the module name.

Plugin or observer

ApproachWhen it fits
ObserverYou need to react to something that has already happened
PluginYou need to change the arguments or the result of a method

Common mistake

Heavy work is done in an observer: sending emails, calling an external service. An observer runs inside the customer's request, and placing an order waits until it finishes. Such work is postponed — into a scheduled job or a message queue, both covered in the cron lesson.

Thanks for reading!

Donate to the site — we work hard for you.