Remplacer la classe abstraite dans Magento 2


13

Dans Magento 1, je pouvais copier la classe abstraite dans un répertoire local ou communautaire et Magento l'a utilisé lors du chargement automatique de cette classe.

Y a-t-il une solution à faire pour que Magento charge ma classe à la place vendor/magento/framework/Model/AbstractModel.php?

Les préférences dans di.xmlles classes abstraites ne fonctionnent pas. Plugins uniquement?

Réponses:


9

Plugins uniquement?

Oui. Vous pouvez écrire des plugins pour les classes abstraites et les plugins doivent toujours être préférés aux préférences si possible.

Les préférences sont utiles si vous souhaitez remplacer une implémentation. Je ne peux pas penser à un cas d'utilisation pour remplacer l'implémentation pour tous les modèles qui s'étendent AbstractModel, si c'est même logiquement possible. Donc, ce que vous voulez probablement, c'est ajouter ou modifier des fonctionnalités et c'est à cela que servent les plugins.


1
Salut, comment puis-je remplacer une fonction protégée de la classe abstraite dans ce cas? pourriez-vous s'il vous plaît aider
Manashvi Birla

2
Ce n'est pas possible. Le mieux est d'essayer de trouver un moyen d'ajouter des plugins aux méthodes publiques qui utilisent la méthode protégée et de changer le comportement de cette manière, même si cela implique plus de code et une certaine duplication.
Fabian Schmengler

1
"Je ne peux pas penser à un cas d'utilisation pour remplacer l'implémentation pour tous les modèles qui étendent AbstractModel" J'ai un tel cas d'utilisation: j'ai un module de paiement, qui utilise une classe de base abstraite pour 4 contrôleurs, chacun utilisant une méthode de base pour vérifier la réponse de la passerelle de paiement. Maintenant, la réponse a changé et je devrais tout changer 3.
Tero Lahtinen

6

Solution complète: incluez les classes remplacées avant que magento ne les charge automatiquement. Donc, étape par étape:

  1. Dans le fichier, app/etc/NonComposerComponentRegistration.phpajouter une ligne

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. En app/etcfichier lieu ClassReplacer.phpavec le contenu

    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. Place à app/code/Magentoune classe, qui sera remplacée, par exempleapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php



1
Hack sale, mais parfois, il pourrait être utile de pouvoir le faire. M1 a exigé des changements manuels dans les classes de base (donc copiez-les dans l'application / le code / local) si vous vouliez que la facture PDF soit différente, je parie qu'il y aura un cas où cela sera nécessaire.
Zefiryn

5

Si la classe abstraite a une méthode publique ou protégée que vous souhaitez remplacer, il existe en fait un moyen si vous ne pouvez pas utiliser de plugins.

J'ai dû remplacer la méthode à l' _processDownloadintérieur \Magento\Downloadable\Controller\Download, en ajoutant des «si-s» à l'intérieur. (Si quelqu'un a une idée de comment ajouter quelque chose comme ça à l'intérieur de la méthode en utilisant des plugins, je serai reconnaissant). La classe est abstraite, donc la préférence n'a pas fonctionné. Plugins aussi, car la méthode est protégée. La chose que je devais faire était de remplacer toutes les classes à partir de Download, en utilisant la préférence. Ces cours:

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

Et à l'intérieur, réécrivez la méthode de la classe parente (celle que je devais remplacer). Donc, en fait, le code des méthodes remplacées a été copié à trois endroits et était exactement le même.

Ce n'est pas idéal mais ça marche.


4

Vous pouvez essayer d'utiliser Magento Plugin pour améliorer les fonctionnalités existantes de n'importe quelle classe abstraite, bien que la portée de la fonction devrait être publique. Récemment, j'ai travaillé sur le même problème où je dois exclure des produits ayant un attribut personnalisé attribué de la liste des produits récemment consultés .

J'ai utilisé le plugin pour la fonction nommée getItemsCollection de la classe nommée Magento \ Reports \ Block \ Product \ AbstractProduct en utilisant la syntaxe suivante:

fichier: app \ code \ Package \ Module \ etc \ frontend \ di.xml

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

fichier: app \ code \ Package \ Module \ Block \ Views.php

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

Vous pouvez également utiliser des plugins avant et avant. J'espère que ce travail pour vous.


1
J'ai obtenu du succès avec le code ci-dessus dans l'une de mes exigences, en fait, je voulais changer certaines fonctionnalités de la méthode de classe abstraite du module de messagerie et le plugin m'a aidé à y parvenir, merci
bhargav shastri
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.