How do you set the sort order for event observers in Magento?
Asked Answered
A

2

14

I have created an observer on the catalog_product_save_after event, but it seems to be getting called before the catalogrule observer that runs the applyAllRulesOnProduct() method. I need to call mine after applyAllRulesOnProduct() runs. How is the order for these observers chosen?

Automate answered 10/4, 2013 at 19:20 Comment(0)
O
36

The answer, like many in Magento, is complicated. There's also two possible problems your specific situation might relate to. This is going to be long — skip to the end for the contextless short version.

Module Loading Order

There is not way to explicitly set an observer sort order. Magento will run through the events in the order they've been merged into the global configuration. So, while you can't control the order of event specifically, you can control the order Magento loads and merges modules in by using the <depends/> tag in your app/etc/modules XML declaration file.

For example, in the Mage_Api2.xml file

<!-- File: app/etc/modules/Mage_Api2.xml -->
<config>
    <modules>
        <Mage_Api2>
            <active>true</active>
            <codePool>core</codePool>
            <depends>
                <Mage_Core />
                <Mage_Oauth />
            </depends>
        </Mage_Api2>
    </modules>
</config>

the author has indicated that the Mage_Api2 module depends on the Mage_Core and Mage_Oauth modules. This means Mage_Api2's config.xml file will be merged after the config.xml files of Mage_Core and Mage_Oauth. This means that events defined in Mage_Api2 will run after events defined in Mage_Core and Mage_Oauth.

Lacking a <depends/> node, the rules for module loading are

  1. All core modules are loaded before non-core modules

  2. The remaining modules are loaded alphabetically.

It would be good form to have your module depend on the Mage_CatalogRule module (where the applyAllRulesOnProduct observer method is defined). However, it should not be necessary, as all core modules are loaded before non-core modules.

That's because there's another factor in the order event observer methods are run in.

Area Order

In addition to module order, you'll also need to consider which area your event observer is defined in. That is, when you create an event observer in Magento, you drop in some config.xml that looks like this

<config>
    <!-- ... -->
    <global>
        <!-- ... -->
        <events>
            <catalog_product_save_after>
                <observers>
                    <abc_abc>
                        <class>abc_abc/observer</class>
                        <method>test</method>
                    </abc_abc>
                </observers>
            </catalog_product_save_after>
        </events>       
    </global>
</config>

In the above example, this event observer has been defined in the global area (because it's inside the <global/> node). This means the observer will run in both the frontend and adminhtml areas of Magento. However, it's also possible to restrict the area your event is run in. For example, the catalogrule event you mentioned is defined in the adminhtml area

<!-- #File: app/code/core/Mage/CatalogRule/etc/config.xml -->
<config>
    <!-- ... -->
    <adminhtml>
        <!-- ... -->
        <events>
            <!-- ... -->
            <catalog_product_save_after>
                <observers>
                    <catalogrule>
                        <class>catalogrule/observer</class>
                        <method>applyAllRulesOnProduct</method>
                    </catalogrule>
                </observers>
            </catalog_product_save_after>
        </events>
    </adminhtml>
</config>

This means this event observer will only run in Magento's backend adminhtml area. In other words, it only runs when you save an event in the backend admin console.

This is where I think your problem is, because in modern versions of Magento (and possibly the old ones), event observers from the <global/> node always run before event observers in the <adminhtml/> node. My guess is your event is in the <global/> node. Try moving it to the <adminhtml/> node.

The Short Version: Make sure your module <depends/> on the Mage_CatalogRule module, and move your event observer configuration to the <adminhtml/> node in your module's config.xml.

Olvan answered 10/4, 2013 at 21:11 Comment(3)
Thank you for the detailed explanation; it makes perfect sense now. Only tweak was to use Mage_CatalogRule (capital "R") for the <depends/>. Works perfectly now. Thanks, again!Automate
Just as a reference, a third option could be: disable the observer from catalogrule ( just set the type>disabled</type in your config.xml for that node) and call the method inside your own observer: Mage::getSingleton('catalogrule/observer')->applyAllRulesOnProduct($event);, at the beginning or the end of your listener (depending what you want of course)Luck
Not an appropriate use of the comments section, but I couldn't resist -- Nearly 10 years into Magento now and I still am discovering helpful write-ups from you @AlanStorm. Be it Magento 1 or Magento 2, thank you for your contributions to the community.Samp
R
3

I know this is an old thread, but in case anyone wants to change the load order of their module:

The /etc/modules/* folder is loaded alphabetically, so if your module's file comes first (or last) it is loaded in that order accordingly- So you could just rename /etc/modules/Namespace_Module.xml to /etc/modules/ZZZNamespace_Module.xml to have it loaded last (assuming there aren't any other modules with ZZZZ...)

Also, to clarify, everything else in your module can remain intact (code/file and folder names), you would just change this one file which can be named anything you choose.

Raving answered 30/10, 2013 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.