There are multiple approaches but I'll start with how it's not done to clarify some common misconceptions:
- It's not possible to override controller classes by copying them to
app/code/local
. This is because controller classes are not loaded by Varien_Autoload
, instead the files are explicitly included.
- It's not recommended to use
<rewrite><controller><to>
syntax anymore. This is an old technique which is obsolete since Magento 1.3 (see: Overwriting controller vs overwriting action controller request)
Add/override controller actions
To add controller actions to an existing controller, use the following in your config.xml:
<frontend> <--- area (adminhtml or frontend)
<routers>
<checkout> <--- front name (in admin always "adminhtml")
<args>
<modules>
<stack_checkout before="Mage_Checkout">Stack_Checkout</stack_checkout>
^ ^
| |
module to override |
</modules> (in admin always |
</args> "Mage_Adminhtml") your module
</checkout>
</routers>
</frontend>
Then create a controller in your module such as
class Stack_Checkout_OnepageController extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
// here you override checkout/onepage/index
}
public function helloAction()
{
// here you create a new action checkout/onepage/hello
}
}
You don't need to extend the original controller class because Magento will look in both classes, in the order defined by before="..."
If you need to extend the original class because you want to reuse other methods from it, you have to include it (remember, controllers are not autoloaded):
require_once(Mage::getModuleDir('controllers','Mage_Checkout') . DS . 'OnepageController.php');
Use observers to modify controller actions
If you don't add new actions, an alternative is to use observers to modify the behavior of existing actions. Every controller action triggers a dynamic "predispatch" event in the form controller_action_predispatch_$FRONTNAME_$CONTROLLER_$ACTION
, for example controller_action_predispatch_checkout_onepage_index
In the observer you have access to the controller class itself using
$controller = $observer->getControllerAction();
If you don't want the original method to be triggered, tell Magento to not further dispatch the action:
$controller->setFlag('', Mage_Core_Controller_Front_Action::FLAG_NO_DISPATCH, true);
For the sake of completeness: You can also prevent "postdispatch" events in a similar way, but this is usually not necessary (here is an example where it's useful: XML has extra content):
$controller->setFlag('', Mage_Core_Controller_Front_Action::FLAG_NO_POST_DISPATCH);
Speaking of which, you can also add an observer for controller_action_postdispatch_$FRONTNAME_$CONTROLLER_$ACTION
if you want to perform additional actions or modifications of the response after the original action has been executed.