Magento – Override Controller and Controller Files

controllersmagento-1magento-enterpriseoverrides

I am trying to override a file in Controller and another in controllers directory of the Amazon Payments module. I have followed several tutorials with no luck at overriding the controllers and I have no idea how to override abstract classes in the Controller folder (capital C). I need to override two methods found in two different files indexAction() in OnepageController.php and _getOnepage() in Checkout.php.

app/code/community/Amazon/Payments/controllers/OnepageController.php

class Amazon_Payments_OnepageController extends Amazon_Payments_Controller_Checkout
{
    ...

    public function indexAction()
    {
        // placeholder required
    }

    ...
}

app/code/community/Amazon/Payments/Controller/Checkout.php

abstract class Amazon_Payments_Controller_Checkout extends Mage_Checkout_Controller_Action
{
    ...

    protected function _getOnepage()
    {
       return Mage::getSingleton('checkout/type_onepage');
    }

    ...
}

Does anyone see what I am doing wrong in my code that would get this working? Also does anyone know how to override the Checkout.php file at the bottom?

app/etc/modules/KNG_Amazon/Payments.xml

<?xml version="1.0"?>
<config>
    <modules>
        <KNG_Amazon_Payments>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Amazon_Payments />
            </depends>
        </KNG_Amazon_Payments>
    </modules>
</config>

app/code/local/KNG/Amazon/Payments/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <KNG_Amazon_Payments>
            <version>1.3.0.1</version>
        </KNG_Amazon_Payments>
    </modules>
    <frontend>
        <routers>
            <amazon_payments>
                <args>
                    <modules>
                        <KNG_Amazon_Payments before="Amazon_Payments">KNG_Amazon_Payments</KNG_Amazon_Payments>
                    </modules>
                </args>
            </amazon_payments>
        </routers>
    </frontend>
</config>

app/code/local/KNG/Amazon/Payments/controllers/OnepageController.php

require_once 'Amazon/Payments/controllers/OnepageController.php';
class KNG_Amazon_Payments_OnepageController extends Amazon_Payments_OnepageController 
{
    public function indexAction()
    {
        $this->_getOnepage()->savePayment(array(
                'method' => 'amazon_payments',
                'additional_information' => array(
                        'order_reference' => $this->getAmazonOrderReferenceId(),
                )
        ));
    }
}

As for this last file I don't have any idea how to override it but the change below to the method is what I am wanting from the result.

app/code/local/KNG/Amazon/Payments/Controller/Checkout.php

abstract class KNG_Amazon_Payments_Controller_Checkout extends Amazon_Payments_Controller_Checkout 
{
    protected function _getOnepage()
    {
        return Mage::getSingleton('amazon_payments/type_checkout');
    }
}

Update: After some research I found out that I no longer need to override Checkout.php file. I like the answer that was given by @fschmengler, explaining the differences so I want to leave it. My problem right now is that my code for OnepageController.php is still not working. Can anyone help with that?

Best Answer

As you noticed, these are two different kinds of controller classes. The actual controllers, loaded by the Magento Router, in controllers and abstract controller classes, loaded by the autoloader in Controller

Controller overrides work as follows:

For each route (like amazon_payments in your case), several modules can register their controllers:

  1. The Amazon_Payments module registers their controllers with prefix Amazon_Payments
  2. Your module registers its controllers with prefix KNG_Amazon_Payments and specifies that they should be used before Amazon_Payments.

Now for each request that starts with the front name of amazon_payments, controllers and actions are searched in this order. A request to amazon_payments/onepage/index will:

  1. look for app/code/local/KNG/Amazon/Payments/controllers/OnepageController.php,
  2. if the file exists, load it and check if the class KNG_Amazon_Payments_OnepageController contains a indexAction method, if yes, execute it and stop (if this class is not defined in the file, throw an error)
  3. look for app/code/community/Amazon/Payments/controllers/OnepageController.php
  4. if the file exists, load it and check if the class Amazon_Payments_OnepageController contains a indexAction method, if yes, execute it and stop (if this class is not defined in the file, throw an error)
  5. forward to noroute action (i.e. show 404 page)

Abstract Controller classes:

For abstract controller classes, this override system does not work, you would have to override each single controller and extend the original class, so that all actions use your controllers. This is the same problem that we have with changing methods in abstract model classes. To avoid duplicate code, you could use traits.

But there is another option: Since classes in the Controller directory are loaded by the autoloader, the directory fallback system can be used. Place your modified abstract controller in app/code/local/Amazon/Payments/Controller/Checkout.php. It must be a modified copy of the original class, not a new class that extends it.

Both solutions are not very pretty, but if you really need to make changes there, you have to choose the lesser of the two evils.

Think about it twice, if you can accomplish your goal with a different method. If the code in the question is your real and complete code, maybe you can override the singleton instead?

Related Topic