2

This is both a question and kind of an answer. But I still would love to find a better solution and you may shed a light on this.

When creating an observer in Magento, the method that is responsible for dispatching it and calling the function that has been configured in the observer's declaration in a module's config.xml file is Mage_Core_Model_App::dispatchEvent.

In this method, there is this codebit which gathers observers information:

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,
    );
}

This codebit means that one may declare an < args > node in an observer like this:

<events>
    <event_to_observe>
        <observers>
            <observer_name>
                <type>singleton</type>
                <class>Namespace_Module_Model_ObserverClass</class>
                <method>observerMethod</method>

                <args>
                    <arg_name>arg_value</arg_name>
                </args>

            </observer_name>
        </observers>
    </event_to_observe>
</events>

Later in the Mage_Core_Model_App::dispatchEvent, we can find some code that is responsible for calling the observers' methods and passing the $observer object as argument.

But, if I am correct, no code sets the $observers[$obsName]['args'] value nor to the $event object, nor to the $observer object. Result is: the < args > node from the observer declaration is not accessible in the observer's called method (Namespace_Module_Model_ObserverClass::observerMethod in my previous example).

My first bet was to try to get the < args > node using something like this:

$args = (array) Mage::getConfig()->getXpath('//events/' . $observer->getEvent()->getName() . '/observers/' . $observer->getName() . '/args');

But, how disappointing, the $name variable (which is also used in Mage_Core_Model_App::dispatchEvent for the profiler) is also not passed to the $observer object... So $observer->getName() is not returning any data.

So I ended up creating a helper method that any oberver method can call in order to retrieve its < args > node. You can find the gist of this helper and how to use it here:

https://gist.github.com/3312869

It would be so easier to have something like this in Mage_Core_Model_App::dispatchEvent: $observer->setMethodArgs($obs['args']) allowing to use $observer->getMethodArgs() in the observer method...

Or maybe did I miss something that allows us to retrieve the < args > node but I'm not sure as, searching thru the Core code, I didn't find any < args > node meaning that Magento does not use this feature in its Core.

So, now, the question is... do you have an easy and Magento Core way to retrieve < args > from an observer declaration ?

burning_LEGION
  • 13,246
  • 8
  • 40
  • 52
Hervé Guétin
  • 4,392
  • 4
  • 29
  • 36
  • I'm curious to know why you are wanting to pass args to an event constructor - what's the use case? – benmarks Aug 10 '12 at 10:19
  • 1
    Use case is that I want to use the same observer method for several events and thus have lighter code. Instead of calling methodForEvent1, methodforEvent2, I want to call methodForEvent($args) – Hervé Guétin Aug 10 '12 at 11:23

1 Answers1

1

The unfortunate disconnect with args is... unfortunate. The <args> node seems vestigial. However, if you have a single method which executes one of several behaviors depending on a param, it might be appropriate to have those distinct activities ensconced in distinct methods. That said, whereas you will need separate and total configuration for each event which you would like to observe/consume with the same method, you have three options:

Call the same method for each event and control the behavior inside the observer method by testing the event name using $observer->getEvent()->getName().

Call a distinct method in each event observer configuration, and have these methods internally call the method which contains the behavior, and simply pass in an argument to indicate which behavior.

Fix your xpath reference to retrieve the args:

Mage::getConfig()->getNode('global/events/'.$observer->getEvent()->getName().'/observers/your_config/args');

or

Mage::getConfig()->getXpath('global/events/'.$observer->getEvent()->getName().'//args');
$args = $cfg[0];

Note that the latter will pick up args from any global observer config for the given event which contains args. You might want to add a node to contain your args inside of the args node and then use that as part of the xpath - though it's unlikely that any other module would use args, let alone pass in params which would affect your module's processing.

benmarks
  • 23,384
  • 1
  • 62
  • 84
  • I noticed this a while back too and was never able to find out how core intended this to be used (have also checked back on all previous versions). It seems logical that it 'could' be used as Hervé wants. I have submitted a pull request to find out - https://github.com/magento/magento2/pull/63 – Drew Hunter Aug 11 '12 at 19:35
  • @benmarks - thanks for your answer for which I'm sure you won't be upset if I cannot consider it as "tickerable" :) Indeed, it doesn't give a clear Magento Core way to retrieve the < args > from the observer and, unfortunately, both of your tricks require to have some known fixed data about the current observer ("your_config" in the first trick, and some fixed children nodes in the second) and thus doesn't allow fully dynamic and factorized way to retrieve the args. So, I will stick to the Gist I provided at https://gist.github.com/3312869. Thanks again anyway! – Hervé Guétin Aug 13 '12 at 06:57
  • @Drew Hunter - that's a great idea to have issued a pull request ! I hope that the Core Team will take it into account or give some explanation if they don't. – Hervé Guétin Aug 13 '12 at 06:58
  • @HervéGuétin I'd only add that you may want to detect/handle the event area to ensure that the correct args are retrieved for an obser + args configured under adminhtml / frontend, but now we're really getting into the edge cases :-) – benmarks Aug 13 '12 at 15:38
  • @bemarks - hey hey :) Nice one on the area part! But still the Gist I posted manages this and, in the end, gathers all args, whatever the area. One may even call the same observer, with the same event, with the same or different < args > on different areas, the Gist will return all of the args in one Varien_Object! – Hervé Guétin Aug 13 '12 at 18:56