Добавление нового метода в абстрактный класс в Magento 2

16

Как сказано в этой теме: переопределить абстрактный класс в Magento 2 в Magento 1 ,

Я могу просто создать новый класс. В Magento 2 нам нужно использовать плагины, но плагины позволяют мне только изменять существующие методы. Что мне делать, если я хочу добавить новый метод?

Пример:

Этот класс vendor/magento/module-ui/Component/AbstractComponent.phpимеет массив компонентов: $componentsнет функции для сброса / удаления элементов этого массива. Итак, как я могу создать эту функцию?

Matias
источник

Ответы:

0

Я не понимаю, как вы можете сделать это без полного переопределения класса. В нашем примере вы можете отключить отдельные компоненты, установив для элемента «disabled» аргумент «data» в XML. Например:

<?xml version="1.0" encoding="UTF-8"?>

<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="general">
        <field name="title">
            <argument name="data" xsi:type="array">
                <item name="disabled" xsi:type="boolean">true</item>
            </argument>
        </field>
    </fieldset>
</form>

Это эффективно удаляет «заголовок» из $componentsмассива.

Это связано с createChildComponentметодом в Magento\Framework\View\Element\UiComponentFactoryклассе:

 protected function createChildComponent(
        array $bundleComponents,
        ContextInterface $renderContext,
        $identifier
    ) {
        list($className, $arguments) = $this->argumentsResolver($identifier, $bundleComponents);
        if (isset($arguments['data']['disabled']) && (int)$arguments['data']['disabled']) {
            return null;
        }
        $components = [];
        foreach ($bundleComponents['children'] as $childrenIdentifier => $childrenData) {
            $children = $this->createChildComponent(
                $childrenData,
                $renderContext,
                $childrenIdentifier
            );
            $components[$childrenIdentifier] = $children;
        }
        $components = array_filter($components);
        $arguments['components'] = $components;
        if (!isset($arguments['context'])) {
            $arguments['context'] = $renderContext;
        }

        return $this->objectManager->create($className, $arguments);
    }
Аарон Аллен
источник
Это не то, что я ищу ... Я хочу добавить новые методы в класс Abstract ... это всего лишь пример ... например, что если я хочу удалить элементы динамически? В своем комментарии вы упоминаете «полное переопределение», как вы это делаете ??
Матиас
Затем вам нужно определить ваши новые методы в классе, который расширяет абстрактный класс, а затем создать классы для подклассов абстрактного класса, которые вместо этого наследуются от вашего класса, и установить предпочтения в di.xml. Это то, что я имею в виду, «полностью перекрывая класс». Я пытался показать пример того, как этого избежать.
Аарон Аллен
Да, я вас понимаю ... но решение вообще не масштабируется ... Я не могу поверить, что M2 исключил возможность переопределения абстрактных классов ... Я думал, что они собираются улучшить его, вместо того, чтобы удалить его ... .
Матиас
0

перегрузка класса в M1 в автозагрузчике через сообщество или локальный каталог (как предложено в вопросе, который вы связали) считалась плохой практикой в ​​M1 по очень веским причинам.

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

На самом деле, я не могу придумать ни одного варианта использования, где вам действительно нужно добавлять методы к абстрактному классу, поскольку вы всегда можете добавить свою собственную логику к собственному классу и интегрировать ее в конфигурацию плагина / наблюдателя / viewModel / xml.

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

Если вам нужно удалить элементы из компонента пользовательского интерфейса, вероятно, есть лучший способ сделать это через макет / плагин в процессоре макетов / изменив файл js, который требует этого.

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

Дэвид Верхолен
источник
Я знаю, что это плохая практика, но, по крайней мере, у вас есть один способ сделать это. Например, рассмотрим случай, когда вы хотите добавить кеш для каждой загружаемой вами модели. Это можно сделать, изменив метод load в абстрактном классе, и тогда это изменение будет распространено на все классы. Если у вас этого нет, вы должны изменить каждую модель, которая у вас есть, и это абсолютно не масштабируется.
Матиас
Второй вариант использования может быть, если вы хотите сделать то, что я говорю в заявке, сбросить / удалить элементы из этого массива (рассмотрим в качестве примера), вы можете подумать о чем-нибудь другом ... вам нужно создать новую функцию в абстрактном классе, в противном случае, вы будете вынуждены создавать одну и ту же функцию в каждом расширяемом классе, и это снова вообще не масштабируется ... И что еще хуже, потому что переменные в ядре Magento являются личными, а не защищенными, поэтому Единственный способ сделать это - добавить метод в абстрактный класс ...
Matias
Первый пример абсолютно прост, просто добавив плагин вокруг к абстрактной модели и кешируя результат загрузки по модели. Что было бы намного лучше, чем перегружать абстрактный класс, который нарушал бы каждое будущее обновление, в котором изменяется абстрактная модель. Ваш второй «пример», о котором я не могу вам много рассказать, потому что вы в основном просите точно добавить метод к абстрактному классу вместо того, чтобы
указывать
Кстати, это все еще возможно в Magento2, потому что вы можете манипулировать автозагрузчиком композитора, но крайне обескуражен, потому что у вас будут проблемы с обновлениями magento.stackexchange.com/questions/164455/…
Дэвид Верхолен
Это не вариант
Матиас