¿Qué hago cuando una extensión sobrescribe una clase globalmente y quiero usar el original?

42

Estamos utilizando una extensión que sobrescribe globalmente el bloque Mage_Catalog_Block_Product_List_Toolbar.

<global>
    <blocks>
        <catalog>
            <rewrite>
                <product_list_toolbar>Amasty_Shopby_Block_Catalog_Product_List_Toolbar</product_list_toolbar>
            </rewrite>
        </catalog>
    </blocks>
</global>

Si bien la extensión funciona en el contexto de una categoría de navegación en capas, la clase reescrita no funciona correctamente cuando insertamos una lista de productos arbitraria en otra vista (personalizada) en nuestro propio módulo interno. Si eliminamos la sobrescritura de la extensión solo con fines de prueba, todo funciona bien.

¿Cómo podemos deshacer la reescritura de una extensión solo para nuestro propio controlador, sin editar el código de comunidad del desarrollador de la extensión?

Aaron Pollock
fuente
2
Si cambia la clase, probablemente romperá la extensión Shopby pero ... Nunca lo haya intentado, sin embargo, es posible que solo desee reescribir esa clase de extensiones en su propia extensión Your_Extension_Block_Catalog_Product_List_Toolbar extiende Amasty_Shopby_Block_Catalog_Product_List_Toolbar
Sander Mangel
Por lo que puedo decir, Magento solo permite uno <rewrite>por clase, por lo que aunque podría crear mi propia clase extendiendo la clase principal, no estoy seguro de cómo hacerlo funcionar a través del getBlock('catalog/product_list_toolbar')método de fábrica.
Aaron Pollock
Si se trata de una extensión paga, debe comunicarse con el soporte de Amasty, esto se ve como un error
Fra
¿lograste identificar el problema? ¿Qué causa el problema que enfrenta (qué función en la clase extendida)?
FlorinelChis
1
@AaronPollock tal vez, pero este problema aún podría surgir de una extensión que sobrescribe las cosas exactamente tan ampliamente como sea necesario. Quizás sería mejor reexaminar el modelo de herencia en sí. Tal vez los mixins o rasgos ayudarán.
kojiro

Respuestas:

25

Advertencias: No hay una forma diseñada para hacer lo que está pidiendo en el sistema. Lo siguiente debería funcionar, pero nunca lo he probado exhaustivamente en un sistema de producción, y puede haber situaciones en las que cause más problemas de lo que vale. Solo proceda si se siente cómodo depurando problemas relacionados con el cambio de reescrituras de un sistema de trabajo.

El paso 1 es deshacer la reescritura. El árbol de configuración de Magento se puede cambiar en tiempo de ejecución. Entonces, si ejecuta el siguiente código

$config = Mage::getConfig();        
$config->setNode(
    'global/blocks/catalog/rewrite/product_list_toolbar',
    'Mage_Catalog_Block_Product_List_Toolbar'
);

Entonces Magento creará una instancia del Mage_Catalog_Block_Product_List_Toolbarbloque original para el resto de la solicitud.

El paso 2 es decidir dónde llamar a esto en su módulo. Dado que esto es solo para su controlador y está reescribiendo un bloque que no se instanciará hasta el final de su controlador, agregaría un método a su clase de controlador algo como esto

protected function _undoRewrites()
{
    $config = Mage::getConfig();        
    $config->setNode(
        'global/blocks/catalog/rewrite/product_list_toolbar',
        'Mage_Catalog_Block_Product_List_Toolbar'
    );    
}

y luego simplemente llame a este método al comienzo de cada una de sus acciones

public function indexAction()
{
    $this->_undoRewrites();
    $test = Mage::getSingleton('core/layout')->createBlock('catalog/product_list_toolbar');        
    var_dump($test);
}

Esto puede parecer un poco torpe, pero creo que es una buena idea ser torpe (es decir, obvio) cuando se es inteligente con los objetos del sistema de Magento. Otro lugar para esto podría ser los eventos controller_action_predispatcho controller_action_predispatch_front_controller_actiony / o aplicados condicionalmente.

Solo recuerde que la reescritura no se deshará hasta que se llame a este método. Eso significa que si intenta crear una instancia de un bloque antes de llamar _undoRewrites, la clase reescrita se usará para crear una instancia del objeto.

Alan Storm
fuente
19

Solución 1:
puede intentar crear una instancia de la clase directamente (forma php) en su controlador

en lugar de

$this->getLayout()->createBlock('catalog/product_list_toolbar');

algo como:

$block = New Magento_Catalog_Product_List_Toolbar;
$this->getLayout()->addBlock(....);

Solución 2:
Otro enfoque sería crear una nueva clase, en su módulo, que extienda la clase original y use esa.

Solución 3: de lo
contrario, si la extensión no está encriptada (a todos nos encanta el código abierto :), puede intentar averiguar por qué rompe sus cosas

Fra
fuente
La solución 2 funciona (solución pragmática) pero no es genial porque no puedo hacer un segundo rewriteen la misma clase base. Por lo tanto, el método de fábrica no funcionará (ya te has dado cuenta de esto). Tal vez no haya una forma de Magento de hacer esto, pero esperemos un poco para ver si hay una mejor manera.
Aaron Pollock
La solución 2 es con lo que iría ... Me estaba preparando para sugerir eso hasta que vi la respuesta de Francesco. ;)
davidalger
1
Aunque me gusta más la solución 2, una nota para la solución 1: también puede proporcionar un nombre de clase completo para createBlock (como $this->getLayout()->createBlock("Mage_Catalog_Block_Product_List_Toolbar")cuando está en un contexto de clase de bloque). Si no hay ningún /parámetro en el parámetro, Magento solo usará la cadena como está para buscar la clase.
Matthias Zeis
1
@ Aaron Pollock, PUEDES hacer una segunda reescritura en la misma clase base. Simplemente nombre el espacio de nombres del módulo como Z (cualquier letra después de A) y magento lo usará en lugar de Amasty one.
Amasty
5

Si existen varias reescrituras para el mismo alias de clase, entonces la última que el cargador de configuración de Magento analiza desde config.xml "gana". Atacaría este problema al:

  1. Crea una nueva extensión propia.
  2. Reescribe el catalog/product_list_toolbaren tu extensión
  3. Haga que su bloqueo se extienda en Mage_Catalog_Block_Product_List_Toolbarlugar de la clase Amasty.
  4. Comenta liberalmente tu clase explicando que este conflicto de reescritura es intencional. No desea que otro desarrollador que ejecuta MageRun intente "arreglar" el conflicto de reescritura que acaba de crear.
  5. Agregue una dependencia en el archivo app / etc / modules / blah.xml de su extensión para asegurarse de que su extensión se cargue después de Amasty.
Jim OHalloran
fuente
1

Similar a lo que sugirió Francesco anteriormente, pero creo que en realidad puedes pasar el nombre completo de la clase a getModel. De esta manera, de alguna manera sigues haciendo lo mismo, pero usando métodos básicos para hacerlo. No estoy completamente seguro de los pros / contras de este método, pero pensé que lo lanzaría como una idea.

Mage::getModel('Mage_Catalog_Block_Product_List_Toolbar');

En una nota al margen, creo que esta será la forma estándar de cargar clases en Magento2.

jmspldnl
fuente
1

Necesito hacer un ligero cambio en el código de extensión, me temo. No reescriba la clase en la suya config.xml, solo cámbiela Amasty_Shopby_Block_Catalog_Product_List_Toolbarpara extender su clase que a su vez se extiende Mage_Catalog_Block_Product_List_Toolbar.

Paul Grigoruta
fuente
Veo el código de extensión como el código central: el negocio de otra persona (para mantener la capacidad de actualizar limpiamente). Debe haber una manera que evite tocarlo. Además, el problema es que la clase Amasty rompe la funcionalidad central en el contexto de una lista arbitraria de productos. No inyecto mi propia funcionalidad; Necesito revivir la funcionalidad principal. Mi propia clase, si siguiera su solución, estaría vacía y cualquier intento de solución que coloque allí sería sobrescrito por la clase Amasty de precedente superior.
Aaron Pollock
Este es un mal hábito. Los módulos externos siempre deben estar intactos. Si necesita actualizar su módulo, deberá rehacer todos sus cambios dentro de la nueva versión. Esto podría convertirse en una pesadilla en términos de mantenibilidad.
Michael Türk el
Será mejor que cree un nuevo bloque y lo extienda DESDE la barra de herramientas de Amasty, no viceversa.
Amasty