Magento Dispatch Event

When Magento dispatches an event, observers can execute code by listening to these events. There are a lot of references to the Magento dispatch event method within Magento. An example of how this might look can be seen below.

Mage::dispatchEvent('some_event_here', $someInformation);

We can look at this method in more depth by navigation to the Mage.php class.

public static function dispatchEvent($name, array $data = array())
{
    Varien_Profiler::start('DISPATCH EVENT:'.$name);
    $result = self::app()->dispatchEvent($name, $data);
    Varien_Profiler::stop('DISPATCH EVENT:'.$name);
    return $result;
}

Take note that the second parameter is of type array. As we can see, the method delegates to the dispatchEvent() method of the Mage_Core_Model_App class.

public function dispatchEvent($eventName, $args)
{
    foreach ($this->_events as $area=>$events) {
        if (!isset($events[$eventName])) {
            $eventConfig = $this->getConfig()->getEventConfig($area, $eventName);
            if (!$eventConfig) {
                $this->_events[$area][$eventName] = false;
                continue;
            }
            $observers = array();
            foreach ($eventConfig->observers->children() as $obsName=>$obsConfig) {
                $observers[$obsName] = array(
                    'type'  => (string)$obsConfig->type,
                    'model' => $obsConfig->class ? (string)$obsConfig->class : $obsConfig->getClassName(),
                    'method'=> (string)$obsConfig->method,
                    'args'  => (array)$obsConfig->args,
                );
            }
            $events[$eventName]['observers'] = $observers;
            $this->_events[$area][$eventName]['observers'] = $observers;
        }
        if (false===$events[$eventName]) {
            continue;
        } else {
            $event = new Varien_Event($args);
            $event->setName($eventName);
            $observer = new Varien_Event_Observer();
        }

        foreach ($events[$eventName]['observers'] as $obsName=>$obs) {
            $observer->setData(array('event'=>$event));
            Varien_Profiler::start('OBSERVER: '.$obsName);
            switch ($obs['type']) {
                case 'disabled':
                    break;
                case 'object':
                case 'model':
                    $method = $obs['method'];
                    $observer->addData($args);
                    $object = Mage::getModel($obs['model']);
                    $this->_callObserverMethod($object, $method, $observer);
                    break;
                default:
                    $method = $obs['method'];
                    $observer->addData($args);
                    $object = Mage::getSingleton($obs['model']);
                    $this->_callObserverMethod($object, $method, $observer);
                    break;
            }
            Varien_Profiler::stop('OBSERVER: '.$obsName);
        }
    }
    return $this;
}

We have a rather large method here, so let’s break it down.

Firstly, the method is wrapped in a foreach loop that loops around the events configuration, whether it be the global, frontend or adminhtml configuration scope.

We then check to see if there is any event configuration available for the event name passed into the dispatchEvent() method. If there isn’t, we set the event name to false and continue with the execution.

$eventConfig = $this->getConfig()->getEventConfig($area, $eventName);
if (!$eventConfig) {
    $this->_events[$area][$eventName] = false;
    continue;
}

We continue and arrive at another foreach loop that loops around the number of observers that are ‘observing’ this event.

foreach ($eventConfig->observers->children() as $obsName=>$obsConfig) {
    $observers[$obsName] = array(
        'type'  => (string)$obsConfig->type,
        'model' => $obsConfig->class ? (string)$obsConfig->class : $obsConfig->getClassName(),
        'method'=> (string)$obsConfig->method,
        'args'  => (array)$obsConfig->args,
    );
}

So we can see here that there are 4 child nodes under the ‘observers’ node that we can use when creating an observer. If you’ve had experience with setting up observers, you’ll know that a standard setup in config.xml would be something along the lines of the below code.

/[Module]/etc/config.xml"]
<?xml version="1.0"?>
<config>
    <frontend>
        <events>
            <some_custom_event>
                <observers>
                    <namespace_somemodule>
                        <type>model</type>
                        <class>namespace_somemodule/observer</class>
                        <method>someObserverMethod</method>
                    </namespace_somemodule>
                </observers>
            </some_custom_event>
        </events>
    <frontend>
<config>

We then arrive at a check to see whether the event name has been set to false (if there was no event configuration found for the event name). If the event name has been set to false, we continue with execution. Else we instantiate a new class of Varien_Event_Observer().

if (false===$events[$eventName]) {
    continue;
} else {
    $event = new Varien_Event($args);
    $event->setName($eventName);
    $observer = new Varien_Event_Observer();
}

Next we then check to see what type our observer is. If it is of type disabled, then we break out of the loop whereas if the observer is of type object, model or it isn’t specified, then we add our arguments that were passed as the second parameter in the dispatchEvent() method and call the _callObserverMethod() method.

foreach ($events[$eventName]['observers'] as $obsName=>$obs) {
    $observer->setData(array('event'=>$event));
    Varien_Profiler::start('OBSERVER: '.$obsName);
    switch ($obs['type']) {
        case 'disabled':
            break;
        case 'object':
        case 'model':
            $method = $obs['method'];
            $observer->addData($args);
            $object = Mage::getModel($obs['model']);
            $this->_callObserverMethod($object, $method, $observer);
            break;
        default:
            $method = $obs['method'];
            $observer->addData($args);
            $object = Mage::getSingleton($obs['model']);
            $this->_callObserverMethod($object, $method, $observer);
            break;
    }
    Varien_Profiler::stop('OBSERVER: '.$obsName);
}

The _callObserverMethod() belongs in the same class as dispatchEvent as seen below.

protected function _callObserverMethod($object, $method, $observer)
{
    if (method_exists($object, $method)) {
        $object->$method($observer);
    } elseif (Mage::getIsDeveloperMode()) {
        Mage::throwException('Method "'.$method.'" is not defined in "'.get_class($object).'"');
    }
    return $this;
}

This method checks to see if the method exists in the observer file, and if it does, we then execute that method, else we throw an exception.

For a guide on how to add an observer in Magento, check out the Add a Magento Observer article.

Note: This article is based on Magento Community/Open Source 1.9.