Как устранить конфликт одновременного перекрывания одного и того же системного класса изменением иерархии наследования?

[10 ноября 2016 г.]    Российская сборка Magento 2.49.12
Magento 2: модули и услуги
#1 Дмитрий Федюк
  • Администратор
  • Иконка
  • Группа: Администратор
  • Сообщений: 8886
  • Регистрация: 20.02.2010

18.01.2014 11:58

Два программных класса в Magento конфликтуют, когда они переопределяют один и тот же системный класс Magento посредством директивы rewrite.
Российская сборка Magento способна обнаруживать такие конфликты.
При обнаружении такого конфликта Российская сборка Magento отображает администратору интернет-магазина сообщение «Системный класс перекрывают конфликтующие между собой классы».

Зачастую конфликт можно устранить изменением иерархии наследования.
Этот способ применим не всегда, но если применим, то, в отличие от других способов, позволяет сохранить функциональность конфликтующих модулей.

Этот способ уже многократно описывалась мной на форуме:

Краткое описание способа:
Для устранения конфликта двойного переопределения системного класса Magento директивой rewrite сторонними модулями А и Б надо:
  • изменить наследование конфликтного класса модуля Б, унаследовав его не от проблемного системного класса, а от конфликтого класса модуля А.
  • гарантировать правильный порядок загрузки (модуль Б должен загружаться после модуля А) директивой depends (пример её применения можно найти в папке app/etc/modules)

Подробное описание способа:
Конфликтующие между собой классы переопределяют один и тот же системный класс Magento и, как правило, оба являются его наследниками.
Посмотрите, какие именно методы системного класса перекрывают конфликтующие между собой классы.
Если эти методы — разные (другими словами, конфликтующие классы не переопределяют один и тот же системный метод), то конфликта можно избежать, унаследовав один конфликтующий класс от другого, а для другого отменить директиву rewrite. Таким образом, первому классу не с кем будет конфликтовать, и в то же время он будет содержать в себе функциональность обоих ранее конфликтовавших классов.

Пошаговая инструкция:
  • Найдите файлы с программным кодом конфликтующих классов по их именам, указанным в диагностическом сообщении.
  • Узнайте классы-родители конфликтующих классов.
    Например, если описание класса начинается так:
    class Df_Adminhtml_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid

    то класс Mage_Adminhtml_Block_Sales_Order_Grid является родителем для класса Df_Adminhtml_Block_Sales_Order_Grid.
    Более подробное описание смотрите в учебнике по PHP.
  • Сравните классы родители конфликтующих классов.
    Описанный в данной статье способ разрешения конфликта применим только когда оба конфликтующих класса имеют одинаковый класс-родитель (в 95% случаев так и есть).
  • Сравните названия методов, описанных в конфликтующих классах.
    Есть ли в конфликтующих классах одноимённые методы?
    Описанный в данной статье способ разрешения конфликта применим только когда оба конфликтующих класса не имеют одноимённых методов с разной реализацией (на практике это обычно так в большей части случаев).
  • Определите, какой из конфликтующих классов станет новым родителем второго из конфликтующих классов.
    Новым родителем можно выбрать любой из конфликтующих классов.
    Например, в инструкции Как добавлять статьи в верхнее товарное меню при использовании модуля TemplateMela TM Custom Menu класс Df_Catalog_Block_Navigation стал новым родителем для класса TM_CustomMenu_Block_Navigation.
  • Смените прежнего родителя (который был общим для конфликтующих классов) на нового родителя (выбранного в предыдущем пункте).
    Например, в инструкции Как добавлять статьи в верхнее товарное меню при использовании модуля TemplateMela TM Custom Menu это делается в пункте 2.
  • Утвердите порядок загрузки конфликтующих модулей посредством директивы depends таким образом, чтобы модуль нового родителя загружался раньше, чем модуль второго конфликтующего класса.
    Например, в инструкции Как добавлять статьи в верхнее товарное меню при использовании модуля TemplateMela TM Custom Menu это делается в пункте 1.

  • **********
    Данный пункт, начиная с версии 2.37.0.6, можно не выполнять, если выполнены оба следующих условия:
    • Конфликтуют только 2 класса (2 модуля)
    • После изменения иерархии наследования сыном стал тот класс, который был основным (активным, используемым системой) при конфликте.

    В такой ситуации Российская сборка Magento «знает», что конфликтующие классы находятся в родственном отношении родитель-сын, и не считает такую ситуацию конфликтом, потому что класс-сын наследует программную реализацию класса-родителя.
    **********
    Удалите директиву rewrite нового родителя.
    Директивы rewrite находятся в основном настроечном файле модуля: etc/config.xml.
    Например, для модуля Df_Catalog основным настроечным файлом является файл app/code/local/Df/Catalog/etc/config.xml
    Основной настроечный файл имеет формат XML.
    Требуемую директивую rewrite в основном настроечном файле можно найти по следующему путю в иерархии тегов XML:
    config/global/<тип класса>/<приставка системного переопределённого класса>/rewrite/<локальное имя системного переопределённого класса>

    Пример директивы rewrite:
    <config>
        <global>
            <blocks>
                <catalog>
                    <rewrite>
                        <navigation>Df_Catalog_Block_Navigation</navigation>
                    </rewrite>
                </catalog>
            </blocks>
        </global>
    </config>

    Для удаления директивы rewrite надо удалить или закомментировать самый внутренний тег и его содержимое. В примере выше это
    <navigation>Df_Catalog_Block_Navigation</navigation>

    Magento кэширует настроечные файлы, поэтому после изменения настроечных файлов надо удалить кэш.
    Также, надо учесть, что выполненные изменения пропадут (перетрутся) после обновления модуля.


Поделиться темой: