Magento: Why do controller action predispatch events not fire if the controller is rewritten?

mattalxndr picture mattalxndr · Jan 8, 2011 · Viewed 9.8k times · Source

Why do controller action predispatch events not fire if the controller is rewritten? Here is a snippet of store/app/code/core/Mage/Core/Controller/Varien/Action.php:

abstract class Mage_Core_Controller_Varien_Action
{
    // [...]
    public function preDispatch()
    {
        // [...]
        if ($this->_rewrite()) {
            return; // [What is the purpose if this?]
        }
        // [...]

        // [This is where my event needs to be firing, but this code never gets 
        // executed because the controller is rewritten]
        Mage::dispatchEvent(
            'controller_action_predispatch_'.$this->getFullActionName(),
            array('controller_action'=>$this)
        );

    }
    // [...]
}

I don't know where to start fixing this problem. Anyone out there ever dealt with this before?

Answer

Alan Storm picture Alan Storm · Jan 8, 2011

No time to test if the the behavior you're describing is accurate, but if it is I imagine it's what happens in the _rewrite function duplicates the actions of other non-event code after that call, and allowing preDispatch to continue after the rewrite would have made "bad things" happen.

In other words, it's a bug in the implementation of controller re-writing that's been ignored, because the preferred way of handling this is now at the routing level. In general, when a system level bug like this makes it into Magento, it tends to stay there, because cart owners start to rely on the broken behavior and scream loudly when anything changes, even if it's a bug fix.

If you can't re-factor your solution as described in the link above, you can still fire the event yourself in the controller class with old fashion Object Oriented Programming. Add the following to your custom controller (the one you're rewriting to)

protected function _rewrite()
{
    //call the parent rewrite method so every that needs
    //to happen happens
    $original_result = parent::_rewrite();

    //fire the event ourselve, since magento isn't firing it
    Mage::dispatchEvent(
        'controller_action_predispatch_'.$this->getFullActionName(),
        array('controller_action'=>$this)
    );      

    //return the original result in case another method is relying on it
    return $original_result;
}