Что мне делать, если расширение перезаписывает класс глобально, и я хочу использовать оригинал?

42

Мы используем расширение, которое глобально перезаписывает блок Mage_Catalog_Block_Product_List_Toolbar.

<global>
    <blocks>
        <catalog>
            <rewrite>
                <product_list_toolbar>Amasty_Shopby_Block_Catalog_Product_List_Toolbar</product_list_toolbar>
            </rewrite>
        </catalog>
    </blocks>
</global>

Хотя расширение работает в контексте многоуровневой категории навигации, переписанный класс не работает должным образом, когда мы вставляем произвольный список продуктов в другое (настраиваемое) представление в нашем собственном внутреннем модуле. Если мы удалим перезапись расширения только для целей тестирования, все будет нормально.

Как мы можем отменить переписывание расширения только для нашего собственного контроллера, не редактируя код сообщества разработчиков расширения?

Аарон Поллок
источник
2
Если вы измените класс, вы, вероятно, сломаете расширение Shopby, но ... Никогда не пытались это сделать, однако вы можете просто перезаписать этот класс расширений в своем собственном расширении. Your_Extension_Block_Catalog_Product_List_Toolbar extends Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel
Из того, что я могу сказать, Magento допускает только один для <rewrite>каждого класса, поэтому, хотя я мог создать свой собственный класс, расширяющий базовый класс, я не уверен, как заставить его работать с помощью getBlock('catalog/product_list_toolbar')фабричного метода.
Аарон Поллок
Если это платное расширение, вы должны обратиться в службу поддержки Amasty, это выглядит как ошибка
Fra
Вам удалось определить проблему? что вызывает проблему, с которой вы сталкиваетесь (какая функция в расширенном классе)?
FlorinelChis
1
Возможно, @AaronPollock, но эта проблема все еще может возникать из-за расширения, которое переписывает вещи так же широко, как и должно. Возможно, нам было бы лучше пересмотреть саму модель наследования. Может быть, миксин или черты помогут.
Кодзиро

Ответы:

25

Предостережения: в системе нет спроектированного способа сделать то, что вы просите. Следующее должно работать, но я никогда не пробовал это на производственной системе, и могут быть ситуации, когда это вызовет больше проблем, чем оно того стоит. Продолжайте, только если вам удобно отлаживать проблемы, связанные с изменением переписывания работающей системы.

Шаг 1 отменяет переписывание. Дерево конфигурации Magento может быть изменено во время выполнения. Итак, если вы запустите следующий код

$config = Mage::getConfig();        
$config->setNode(
    'global/blocks/catalog/rewrite/product_list_toolbar',
    'Mage_Catalog_Block_Product_List_Toolbar'
);

Затем Magento создаст исходный Mage_Catalog_Block_Product_List_Toolbarблок для оставшейся части запроса.

Шаг 2 решает, где вызвать это в вашем модуле. Так как это только для вашего контроллера, и он переписывает блок, который не будет создан до конца вашего контроллера, я бы добавил метод к вашему классу контроллера примерно так

protected function _undoRewrites()
{
    $config = Mage::getConfig();        
    $config->setNode(
        'global/blocks/catalog/rewrite/product_list_toolbar',
        'Mage_Catalog_Block_Product_List_Toolbar'
    );    
}

а затем просто вызовите этот метод в начале каждого из ваших действий

public function indexAction()
{
    $this->_undoRewrites();
    $test = Mage::getSingleton('core/layout')->createBlock('catalog/product_list_toolbar');        
    var_dump($test);
}

Это может показаться немного неуклюжим, но я думаю, что неплохо быть неуклюжим (то есть очевидным), когда вы хорошо разбираетесь в системных объектах Magento. Другим местом для этого могут быть controller_action_predispatchили controller_action_predispatch_front_controller_actionсобытия и / или условия применения.

Просто помните, что перезапись не будет отменена, пока не будет вызван этот метод. Это означает, что если вы попытаетесь создать экземпляр блока перед вызовом _undoRewrites, переписанный класс будет использован для создания объекта.

Алан Сторм
источник
19

Решение 1.
Вы можете попытаться создать экземпляр класса напрямую (php way) в вашем контроллере.

вместо того

$this->getLayout()->createBlock('catalog/product_list_toolbar');

что-то типа:

$block = New Magento_Catalog_Product_List_Toolbar;
$this->getLayout()->addBlock(....);

Решение 2.
Другой подход заключается в создании нового класса в вашем модуле, который расширяет исходный класс и использует его.

Решение 3.
В противном случае, если расширение не зашифровано (мы все любим открытый исходный код :), вы можете попытаться выяснить, почему оно ломает ваши данные

От
источник
Решение 2 действительно работает (прагматичное решение), но оно не очень хорошо, потому что я не могу сделать секунду rewriteв том же базовом классе. Поэтому фабричный метод не сработает (вы уже поняли это, я думаю, уже). Возможно, нет никакого Magento способа сделать это, но давайте немного подождем, чтобы увидеть, есть ли лучший способ.
Аарон Поллок
Решение 2 - это то, с чем я бы пошел ... Я собирался предложить это, пока не увидел ответ Франческо. ;)
Давидгер
1
Хотя решение 2 мне нравится больше всего, примечание к решению 1: вы также можете предоставить полное имя класса для createBlock (например, $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")когда вы находитесь в контексте класса блока). Если его нет /в параметре, Magento просто использует строку как есть для поиска класса.
Матиас Цейс
1
@ Аарон Поллок, вы МОЖЕТЕ сделать второе переписывание в том же базовом классе. Просто назовите пространство имен модуля как Z (любая буква после A), и magento будет использовать его вместо Amasty.
Amasty
5

Если существует несколько перезаписей для одного и того же псевдонима класса, то последний из них, загрузчик конфигурации Magento, анализирует из config.xml "wins". Я бы напал на эту проблему:

  1. Создайте новое собственное расширение.
  2. Перепишите catalog/product_list_toolbarв своем расширении
  3. Пусть ваш блок расширяется Mage_Catalog_Block_Product_List_Toolbarвместо класса Amasty.
  4. Обязательно прокомментируйте ваш класс, объяснив, что этот конфликт переписывания является преднамеренным. Вам не нужен другой разработчик, который запускает MageRun, чтобы попытаться «исправить» конфликт переписывания, который вы только что создали.
  5. Добавьте зависимость в файл app / etc / modules / blah.xml вашего расширения, чтобы убедиться, что ваше расширение загружено после Amasty.
Джим Охаллоран
источник
1

Подобно тому, что предложил Франческо выше, но я полагаю, что вы действительно можете передать полное имя класса в getModel. Таким образом, вы все еще делаете то же самое, но используете для этого основные методы. Я не совсем уверен в плюсах / минусах этого метода, но подумал, что я выброшу это как идею.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

Кстати, я считаю, что это будет стандартный способ загрузки классов в Magento2.

jmspldnl
источник
1

Я боюсь, что вам нужно немного изменить код расширения. Не переписывайте класс по-своему config.xml, просто измените его, Amasty_Shopby_Block_Catalog_Product_List_Toolbarчтобы расширить класс, который, в свою очередь, расширяется Mage_Catalog_Block_Product_List_Toolbar.

Пол Григорута
источник
Я вижу код расширения как основной код - чужое дело (чтобы поддерживать возможность чистого обновления). Должен быть способ избежать этого. Также проблема в том, что класс Amasty нарушает основные функциональные возможности в контексте произвольного списка продуктов. Я не для того, чтобы вводить свою собственную функциональность; Мне нужно оживить основной функционал. Мой собственный класс, если бы я следовал вашему решению, был бы пустым, и любая попытка исправить, которую я там вставил, была бы перезаписана классом Amasty с более высоким прецедентом.
Аарон Поллок
Это плохая привычка. Внешние модули всегда должны быть нетронутыми. Если вам нужно обновить свой модуль, вам нужно будет повторить все ваши изменения в новой версии. Это может стать кошмаром с точки зрения ремонтопригодности.
Майкл Тюрк
Лучше создать новый блок и расширить его с панели инструментов Amasty, а не наоборот.
Amasty