Extand Magento Core Controller или как расширить/переписать контроллер на примере OnepageController.php

Добрый день. Много вопросов возникает на тему того , как же правильно расширить или переписать контроллер ядра Magento. Давайте возмем в пример OnpageController.php который используется в Checkout процессе.  Находится он тут app/code/core/Mage/Checkout/controllers/OnepageController.php
Для решения это задачи вы должны определить для себя в рамках чего Вам это требуется. Если Вы планируете изменить какой-то базовый функционал не имея своего модуля или просто нужно внести правку ,  то конечно для этого можно и в ядре поправить но это абсолютно нелогично, так как существует как минимум два способа, один нормальный и второй правильный. Так вот, если Вам нужно просто внести небольшие правки Вы можете использовать первый способ №1 описанный ниже, а если вы создали свой модуль и его логика подразумевает внесение изменений в процесс чекаута, тогда Ваш путь — способ №2  и это будет самое правильное решение.

Для того чтобы внести небольшую ясность, опишу совсем немного теории «как это работает».
Насколько нам известно в коде Magento есть три codepools (кодпула) находящиеся тут app/code,  базовые пулы это Community, Core, Local.
Selection_001

Такая структура создана для того , чтобы упростить кастомизацию кода и практически полностью изолировать ядро CMS для удобного обновления его командой Magento. Загружая какие либо классы система имеет такой приоритет: сначала она смотрит в папку Local, Далее Comunity и уже после Core. Происходит это в файле Mage.php по пути app/Mage.php. Если Вы откроете  то можно увидеть следущую запись:

    /**
     * Set include path
     */
    $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local';
    $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community';
    $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core';
    $paths[] = BP . DS . 'lib';

    $appPath = implode(PS, $paths);
    set_include_path($appPath . PS . Mage::registry('original_include_path'));
    include_once "Mage/Core/functions.php";
    include_once "Varien/Autoload.php";

Здесь видно что первым делом интерпретатор отрабатывает папку local после community и уже в конце core.

Ну а теперь давайте приступим:
СПОСОБ №1.
Задача внести изменения в код контроллера ядра app/code/core/Mage/Checkout/controllers/OnepageController.php не затрагивая код ядра.
Для этого в папке local дублируем путь к контролллеру создав точно такую же иерархию папок как ядре и копируем туда файл контроллера. Должно получится так app/code/local/Mage/Checkout/controllers/OnepageController.php и все.  После того как вы выполните такие несложные действие каждый раз Magento будет первым делом смотреть в папку local и видеть там OnepageController.php. Это просто способ но он имеет один минус. Если Вам потребуется обновить ядро Magento, то вероятно что Ваш скопированный контроллер будет уже не актуальный, так как команда Magento могла в обновлении внести в него изминения. Для того чтобы этого не случалось, каждый раз после обновлеения CMS magento до крайней версии проверяйте актуальность Вашего контроллера с аналогичным в ядре.

СПОСОБ №2.
У Вас есть свой модулю и Вам нужно внести изменения в код контроллера ядра app/code/core/Mage/Checkout/controllers/OnepageController.php не затрагивая код ядра.
Для этого вы можете его расширить. Делается это следущим образом.

  1. Откройте config.xml вашего модуля и добавте в него следующю запись в тег <global>
    <frontend>
        <routers>
            <checkout>
                <args>
                    <modules>
                        <CodePool_Module before="Mage_Checkout">CodePool_Module_Checkout</CodePool_Module>
                    </modules>
                </args>
            </checkout>
        </routers>
    </frontend>

Должно получится так:

<?xml version="1.0"?>
<config>
    <modules>
        <CodePool_Module>
            <version>0.0.1</version>
        </CodePool_Module>
    </modules>
    <global>
    <frontend>
        <routers>
            <checkout>
                <args>
                    <modules>
                        <CodePool_Module before="Mage_Checkout">CodePool_Module_Checkout</CodePool_Module>
                    </modules>
                </args>
            </checkout>
        </routers>
    </frontend>
</config>

Этим мы сообщим Magento что прежде чем обращаться в модуль Mage_Checkout за кодом, посмотри пожалуйста сперва вот сюда

CodePool_Module_Checkout

может быть там что-то будет.

  1. Создаем файл контроллера по пути app/code/local/CodePool/Module/controllers/Checkout/OnepageController.php и экстендим его от нашего контроллера  из ядра, должно получится так:
<?php

require_once 'Mage/Checkout/controllers/OnepageController.php';

class CodePool_Module_Checkout_OnepageController extends Mage_Checkout_OnepageController
{

}

Теперь вот сюда можно добавлять свои методы которы будут доступны на уровне ядра или в $this на процессе чекаута, то есть ваш контроллер становится полноправным наследником  Mage_Checkout_OnepageController. Но и это еще не все, теперь в  своем контроллере вы имеете возможность  переопределить метод из контроллера ядра. Например, выходите внести изменения в уже существующий метод, допустим

public function saveShippingMethodAction()

Для этого Вам достаточно скопировать весь метод в свой контроллер и сделать изменения. Magento первым делом будет обращаться в Ваш метод так как ее иерархия, если вы не забыли local, community, core.

<?php

require_once 'Mage/Checkout/controllers/OnepageController.php';

class CodePool_Module_Checkout_OnepageController extends Mage_Checkout_OnepageController
{

public function saveShippingMethodAction()
    {
        if ($this->_expireAjax()) {
            return;
        }
        if ($this->getRequest()->isPost()) {
            $data = $this->getRequest()->getPost('shipping_method', '');
            $result = $this->getOnepage()->saveShippingMethod($data);
            /*
            $result will have erro data if shipping method is empty
            */
            if(!$result) {
                Mage::dispatchEvent('checkout_controller_onepage_save_shipping_method',
                    array('request'=>$this->getRequest(),
                        'quote'=>$this->getOnepage()->getQuote()));
                $this->getOnepage()->getQuote()->collectTotals();
                $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
                $this->loadLayout('checkout_onepage_review');
                $result['goto_section'] = 'review';
                $result['update_section'] = array(
                    'name' => 'review',
                    'html' => $this->_getReviewHtml()
                );
            }
            $this->getOnepage()->getQuote()->collectTotals()->save();
            $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
        }
    }
}

Теперь можно спокойно что-то изменять, не боясь что где-то чтото сломается.
На этом все,  удачи.

Оставьте комментарий