Events and observers

Magento implements the observer pattern through MagentoFrameworkEventManagerInterface. In app/etc/di.xml, there is a preference for ManagerInterface that points to the MagentoFrameworkEventManagerProxy class type. The Proxy class further extends the MagentoFrameworkEventManager class that implements the actual event dispatch method.

Events are dispatched by calling a dispatch method on the instance of the EventManager class and passing the name and some data, which is optional, to it. Here's an example of a Magento core event:

$this->eventManager->dispatch(
    'customer_customer_authenticated',
    ['model' => $this->getFullCustomerObject($customer), 'password' => $password]
);

The $this->eventManager is an instance of the previously mentioned EventManager class. In this case, the event name equals to customer_customer_authenticated, while the data passed to the event is the array with two elements. The preceding event is fired when the authenticate method is called on MagentoCustomerModelAccountManagement, that is, when a customer logs in.

Dispatching an event only makes sense if we expect someone to observe it and execute their code when the event is dispatched. Depending on the area from which we want to observe events, we can define observers in one of the following XML files:

  • app/code/{vendorName}/{moduleName}/etc/events.xml
  • app/code/{vendorName}/{moduleName}/etc/frontend/events.xml
  • app/code/{vendorName}/{moduleName}/etc/adminhtml/events.xml

Let's define an observer that will log an e-mail address of an authenticated user into a var/log/system.log file. We can use the Foggyline_Office module and add some code to it. As we are interested in the storefront, it makes sense to put the observer in the etc/frontend/events.xml module.

Let's define the app/code/Foggyline/Office/etc/frontend/events.xml file with content, as follows:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework: Event/etc/events.xsd">
    <event name="customer_customer_authenticated">
        <observer name="foggyline_office_customer_authenticated" instance="FoggylineOfficeObserverLogCustomerEmail" />
    </event>
</config>

Here, we are specifying a foggyline_office_customer_authenticated observer for the customer_customer_authenticated event. The observer is defined in the LogCustomerEmail class that is placed in the Observer module directory. The Observer class has to implement the MagentoFrameworkEventObserverInterface class. The Observer interface defines a single execute method. The execute method hosts the observer code and is executed when the customer_customer_authenticated event is dispatched.

Let's go ahead and define the FoggylineOfficeObserverLogCustomerEmail class in the app/code/Foggyline/Office/Observer/LogCustomerEmail.php file, as follows:

namespace FoggylineOfficeObserver;

use MagentoFrameworkEventObserverInterface;

class LogCustomerEmail implements ObserverInterface
{
    protected $logger;

    public function __construct(
        PsrLogLoggerInterface $logger
    )
    {
        $this->logger = $logger;
    }

    /**
     * @param MagentoFrameworkEventObserver $observer
     * @return self
     */
    public function execute(MagentoFrameworkEventObserver $observer)
    {
        //$password = $observer->getEvent()->getPassword();
        $customer = $observer->getEvent()->getModel();
        $this->logger->info('FoggylineOffice: ' . $customer-> getEmail());
        return $this;
    }
}

The execute method takes a single parameter called $observer of the MagentoFrameworkEventObserver type. The event that we are observing is passing two pieces of data within the array, namely the model and password. We can access this by using the $observer->getEvent()->get{arrayKeyName} expression. The $customer object is an instance of the MagentoCustomerModelDataCustomerSecure class, which contains properties such as email, firstname, lastname, and so on. Thus, we can extract the e-mail address from it and pass it to logger's info method.

Now that we know how to observe existing events, let's see how we can dispatch our own events. We can dispatch events from almost anywhere in the code, with or without data, as shown in the following example:

$this->eventManager->dispatch('foggyline_office_foo');
// or
$this->eventManager->dispatch(
    'foggyline_office_bar',
    ['var1'=>'val1', 'var2'=>'val2']
);

It is worth noting that there are two types of events; we can group them in the following way according to the way their name is assigned:

  • Static: $this->eventManager->dispatch('event_name', ...)
  • Dynamic: $this->eventManager->dispatch({expression}.'_event_name', ...)

The static events have a fixed string for a name, while the dynamic ones have a name that is determined during the runtime. Here's a nice example of the core Magento functionality from the afterLoad method that is defined under lib/internal/Magento/Framework/Data/AbstractSearchResult.php, which showcases how to use both types of events:

protected function afterLoad()
{
    $this->eventManager->dispatch ('abstract_search_result_load_after', ['collection' => $this]);
    if ($this->eventPrefix && $this->eventObject) {
        $this->eventManager->dispatch($this->eventPrefix . '_load_after', [$this->eventObject => $this]);
    }
}

We can see a static event (abstract_search_result_load_after) and a dynamic event ($this->eventPrefix . '_load_after'). The $this->eventPrefix is an expression that gets evaluated during the runtime. We should be careful when using dynamic events as they are triggered under multiple situations. Some interesting dynamic events are the one defined on classes like the following ones:

  • MagentoFrameworkModelAbstractModel
    • $this->_eventPrefix . '_load_before'
    • $this->_eventPrefix . '_load_after'
    • $this->_eventPrefix . '_save_commit_after'
    • $this->_eventPrefix . '_save_before'
    • $this->_eventPrefix . '_save_after'
    • $this->_eventPrefix . '_delete_before'
    • $this->_eventPrefix . '_delete_after'
    • $this->_eventPrefix . '_delete_commit_after'
    • $this->_eventPrefix . '_clear'
  • MagentoFrameworkModelResourceModelDbCollectionAbstractCollection
    • $this->_eventPrefix . '_load_before'
    • $this->_eventPrefix . '_load_after'
  • MagentoFrameworkAppActionAction
    • 'controller_action_predispatch_' . $request-> getRouteName()
    • 'controller_action_predispatch_' . $request-> getFullActionName()
    • 'controller_action_postdispatch_' . $request-> getFullActionName()
    • 'controller_action_postdispatch_' . $request-> getRouteName()
  • MagentoFrameworkViewResultLayout
  • 'layout_render_before_' . $this->request-> getFullActionName()

These events are fired on the model, collection, controller, and layout classes, which are probably among the most used backend elements that often require observing and interacting. Even though we can say that the full event name is known during the runtime along with the dynamic event, this can be assumed even before the runtime.

For example, assuming that we want to observe 'controller_action_predispatch_' . $request->getFullActionName() for the Foggyline_Office module's Crud controller action, the actual full event name will be 'controller_action_predispatch_foggyline_office_test_crud', given that $request->getFullActionName() will resolve to foggyline_office_test_crud during the runtime.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.93.44