Reemplazar clase abstracta en Magento 2

13

En Magento 1, pude copiar la clase abstracta en el directorio local o comunitario y Magento la usó cuando la carga automática cargaba esta clase.

¿Hay alguna solución que hacer para que Magento cargue mi clase en su lugar vendor/magento/framework/Model/AbstractModel.php?

Las preferencias di.xmlpara clases abstractas no funcionan. Solo complementos?

goral
fuente

Respuestas:

9

Solo complementos?

Si. Puede escribir complementos para clases abstractas y los complementos siempre deben preferirse a las preferencias si es posible.

Las preferencias son útiles si desea reemplazar una implementación. No puedo pensar en un caso de uso para reemplazar la implementación de todos los modelos que se extienden AbstractModel, si eso es lógicamente posible. Entonces, lo que probablemente desee es agregar o cambiar la funcionalidad y para eso están los complementos.

Fabian Schmengler
fuente
1
Hola, ¿cómo puedo anular una función protegida de la clase abstracta en este caso? ¿podría ayudar por favor
Manashvi Birla
2
Eso no es posible. Lo mejor es tratar de encontrar una manera de agregar complementos a los métodos públicos que usan el método protegido, y cambiar el comportamiento de esta manera, incluso si implica más código y alguna duplicación.
Fabian Schmengler
1
"No puedo pensar en un caso de uso para reemplazar la implementación de todos los modelos que extienden AbstractModel" Tengo un caso de uso: tengo un módulo de pago, que usa la clase base abstracta para 4 controladores, cada uno con un método de base para verificar La respuesta de la pasarela de pago. Ahora, la respuesta ha cambiado y tendría que cambiar todos los 3.
Tero Lahtinen
6

Solución completa: incluya las clases reemplazadas antes de que magento las cargue automáticamente. Entonces paso a paso:

  1. En el archivo app/etc/NonComposerComponentRegistration.phpagregar fila

    $pathList[] = dirname(__DIR__) . '/etc/ClassReplacer.php';
  2. En app/etcarchivo de lugar ClassReplacer.phpcon el contenido

    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. Coloque en app/code/Magentoalguna clase, que será reemplazada, por ejemploapp/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php

goral
fuente
1
Hack sucio, pero algunas veces puede ser útil poder hacer eso. M1 requirió cambios manuales en las clases principales (por lo tanto, copie a la aplicación / código / local) si desea que el PDF de la factura se vea diferente, apuesto a que habrá algún caso en el que será necesario.
Zefiryn
5

Si la clase abstracta tiene algún método público o protegido que desea anular, existe una forma en realidad si no puede usar complementos.

Tuve que anular el método _processDownloaddentro \Magento\Downloadable\Controller\Download, agregando algunos 'if-s' dentro. (Si alguien tiene idea de cómo puedo agregar algo como este método interno usando complementos, lo agradeceré). La clase es abstracta, por lo que la preferencia no funcionó. Complementos también, ya que el método está protegido. Lo que tenía que hacer era anular todas las clases desde Download, usando preferencia. Estas clases:

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

Y dentro de ellos reescribe el método de la clase padre (el que se suponía que debía anular). Entonces, el código de los métodos anulados se copió en tres lugares y fue exactamente el mismo.

No es ideal pero funciona.

Bartosz Kubicki
fuente
4

Puede intentar usar el complemento Magento para mejorar la funcionalidad existente de cualquier clase abstracta, aunque el alcance de la función debe ser público. Recientemente trabajé en el mismo problema en el que necesito excluir productos que tienen un atributo personalizado asignado de la lista de productos vistos recientemente .

Usé el complemento para la función llamada getItemsCollection de la clase llamada Magento \ Reports \ Block \ Product \ AbstractProduct usando la siguiente sintaxis:

archivo: aplicación \ código \ Paquete \ 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>

archivo: aplicación \ código \ Paquete \ Módulo \ Bloque \ Visto.php

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

Puedes usar plugins tanto como antes como también. Espero que esto funcione para ti.

Sumit Verma
fuente
1
obtuve éxito con el código anterior en uno de mis requisitos, en realidad quería cambiar algunas funcionalidades del método de clase abstracta del módulo de correo electrónico y Plugin me ayudó a lograr esto, gracias
bhargav shastri