Substituir classe abstrata no Magento 2

13

No Magento 1, eu podia copiar a classe abstrata para o diretório local ou comunitário e o Magento a usava, quando o carregamento automático carregava essa classe.

Existe alguma solução para o Magento carregar minha classe vendor/magento/framework/Model/AbstractModel.php?

As preferências di.xmlpara classes abstratas não funcionam. Apenas plugins?

goral
fonte

Respostas:

9

Apenas plugins?

Sim. Você pode escrever plug-ins para classes abstratas e os plug-ins sempre devem ter preferência sobre as preferências, se possível.

As preferências são úteis se você deseja substituir uma implementação. Não consigo pensar em um caso de uso para substituir a implementação de todos os modelos que se estendem AbstractModel, se isso for logicamente possível. Então o que você provavelmente quer é adicionar ou alterar a funcionalidade e é para isso que servem os plugins.

Fabian Schmengler
fonte
1
Oi, como posso substituir uma função protegida da classe abstrata neste caso? você poderia por favor me ajude
Manashvi Birla
2
Isso não é possível. O melhor é tentar encontrar uma maneira de adicionar plug-ins aos métodos públicos que usam o método protegido e alterar o comportamento dessa maneira, mesmo que envolva mais código e alguma duplicação.
Fabian Schmengler
1
"Não consigo pensar em um caso de uso para substituir a implementação de todos os modelos que estendem o AbstractModel". Tenho um caso de uso: Tenho um módulo de pagamento, que usa a classe base abstrata para 4 controladores, cada um usando um método da base para verificar a resposta do gateway de pagamento. Agora, a resposta mudou e eu teria que mudar todos os 3. #
Tero Lahtinen
6

Solução completa: inclua classes substituídas antes que o magento as carregue automaticamente. Então, passo a passo:

  1. No arquivo app/etc/NonComposerComponentRegistration.phpadicionar linha

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. No app/etcarquivo de lugar ClassReplacer.phpcom o conteúdo

    class ClassReplacer
    {
        public function includeReplacedFiles($src)
        {
            try {
                $replacedFiles = $this->listDir($src, false, true);
                foreach ($replacedFiles as $replacedFile) {
                    include_once $src . $replacedFile;
                }
            } catch (Exception $e) {
                return;
            }
        }
    
        protected function listDir($dir, $prependDir = false, $recursive = false, $entityRegexp = null, $currPath = '')
        {
            if (!is_dir($dir)) {
                return array();
            }
            $currPath = $prependDir ? $dir : $currPath;
            $currPath = $currPath !== '' ? rtrim($currPath, '/') . '/' : '';
            $files = array();
            foreach (scandir($dir) as $file) {
                if (in_array($file, array('.', '..'))) {
                    continue;
                }
                $entity = $currPath . $file;
                if ($recursive && is_dir("$dir/$file")) {
                    $files = array_merge($files, $this->listDir("$dir/$file", false, true, $entityRegexp, $entity . '/'));
                    continue;
                }
                if ($entityRegexp && !preg_match($entityRegexp, $entity)) continue;
                $files[] = $entity;
            }
            return $files;
        }
    }
    $replace = new ClassReplacer();
    $replace->includeReplacedFiles(dirname(__DIR__) . '/code/Magento/');
  3. Lugar para app/code/Magentoalguma classe, que será substituída, por exemploapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php

goral
fonte
1
Hack sujo, mas algumas vezes pode ser útil poder fazer isso. O M1 exigiu alterações manuais nas classes principais (copie para app / code / local) se você quiser que o PDF da fatura pareça diferente, aposto que haverá alguns casos em que isso será necessário.
Zefiryn
5

Se a classe abstrata tiver algum método público ou protegido que você queira substituir, existe uma maneira de não usar plug-ins.

Eu tive que substituir o método por _processDownloaddentro \Magento\Downloadable\Controller\Download, adicionando alguns 'se-s' por dentro. (Se alguém tiver idéia de como posso adicionar algo como este método interno usando plug-ins, ficarei grato). A classe é abstrata, então a preferência não funcionou. Plugins também, como o método está protegido. O que eu precisava fazer era substituir todas as classes que estendiam Download, usando a preferência. Essas classes:

Magento\Downloadable\Controller\Download\Link Magento\Downloadable\Controller\Download\LinkSample Magento\Downloadable\Controller\Download\Sample

E dentro deles reescrevemos o método da classe pai (a que eu deveria substituir). Na verdade, o código dos métodos substituídos foi copiado para três lugares e era exatamente o mesmo.

Não é o ideal, mas funciona.

Bartosz Kubicki
fonte
4

Você pode tentar usar o Magento Plugin para aprimorar a funcionalidade existente de qualquer classe Abstract, embora o escopo da função deva ser Público. Recentemente, trabalhei no mesmo problema em que preciso excluir produtos com um atributo personalizado atribuído na lista de produtos visualizados recentemente .

Eu usei o plug-in para a função chamada getItemsCollection da classe Magento \ Reports \ Block \ Product \ AbstractProduct usando a seguinte sintaxe:

arquivo: app \ código \ Pacote \ Módulo \ etc \ frontend \ di.xml

<type name="Magento\Reports\Block\Product\AbstractProduct">
    <plugin name="Package_Module::aroundGetItemsCollection" type="Package\Module\Block\Viewed" sortOrder="20"/>
</type>

file: app \ code \ Package \ Module \ Block \ Viewed.php

public function afterGetItemsCollection(
    $subject, $result
) {
    $result = $result->addAttributeToFilter('skip_hire_product', [['neq' => 1], ['null' => true]], 'left');
    return $result;
}

Você também pode usar plugins anteriores e anteriores. Espero que este trabalho para você.

Sumit Verma
fonte
1
eu tenho sucesso com código acima em uma das minha obrigação, na verdade eu queria mudar algumas funcionalidades do método módulo de e-mail abstract class e Plugin me ajudou a conseguir isso, graças
Bhargav shastri