Cómo agregar controladores de diseño personalizados mediante programación para la Vista de categoría en Magento 2

9

Por lo tanto, quiero agregar un controlador de diseño personalizado para todas las páginas de vista de categoría ... el controlador que se supone que se carga depende de ciertos parámetros de categoría, por lo que el controlador debe agregarse programáticamente con $page->addPageLayoutHandles()

Parece fácil ..? Aparentemente no

Magento 2 proporciona un buen sistema de complementos que naturalmente iba a utilizar, solo defina un afterExecute()complemento para que se ejecute después de la categoría original execute()e inserte cualquier actualización en el objeto Page desde allí.

Desafortunadamente, no funciona de esa manera ... la razón es que execute()se ejecutará el método original (al final) $page->getConfig()->addBodyClass(): una llamada a este método obligará automáticamente a que el diseño se cargue y genere por completo, por lo que cualquier intento posterior de agregar nuevos los controladores de diseño de la página son completamente inútiles. Miré a mi alrededor para encontrar formas no tan elegantes de lograr lo mismo (todavía usando complementos) ... no encontré ninguna.

Terminé ejecutando mi propio controlador para la vista de categoría, sin embargo, no preferiría dejarlo así.

Entonces mi pregunta es ... ¿cómo puedo agregar nuevos controladores de diseño de página (programáticamente) para la vista de categoría? y hazlo con elegancia.

Kristjan H.
fuente
¿Qué versión de Magento estás usando? Porque ¿dónde puedes ver que $page->getConfig()->addBodyClass()carga y genera tu diseño? Tengo una tarea similar en este momento, solo con páginas CMS.
Giel Berkers
Estoy tan contento de que hayas notado esto, ya que me ahorraste mucho dolor. Solo para su información: el controlador de vista de categoría también llama a $ page-> getConfig () -> addBodyClass (), lo que hace que un complemento sea inútil para lograr esto.
Perry Holden

Respuestas:

17

La manera XML

Bueno, una manera fácil es crear el siguiente archivo en la carpeta de su módulo: view/frontend/layout/catalog_category_view.xmlcon el siguiente contenido:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="your_custom_handle"/>
</page>

No es más o menos elegante que la forma PHP y de acuerdo con lo que encontró es más seguro.

La manera PHP

Desafortunadamente en su caso, parece que PHP es la única forma de lograr crear dinámicamente identificadores basados ​​en los parámetros que tiene la categoría.

A través de complementos

En lugar de crear un complemento en el execute()método de su clase de acción, puede crear directamente un complemento en el addPageLayoutHandles()método deMagento\Framework\View\Result\Page

El problema principal es que se llamará cada vez que se llame a este método y tendrá que agregar algunas condiciones en su código de complemento para asegurarse de estar en una página de vista de categoría.

Por preferencias

Otra forma de hacerlo sería usar las preferencias para la clase de acción de vista de categoría:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Controller\Category\View"
                type="Vendor\Module\Controller\Category\View"/>
</config>

Luego, en su clase de controlador personalizado, simplemente anule el execute()método copiando / pegando el método original y agregue sus modificaciones directamente en este método.

El problema principal es que cuando actualice su instalación de Magento, si se agregan cambios a la clase de acción original de Magento, no se reflejará en su clase de acción personalizada.

Raphael en Digital Pianism
fuente
El problema es ... necesita ser agregado programáticamente. Simplemente porque el identificador que se está cargando depende de los parámetros que tenga la categoría.
Kristjan H.
@KristjanH. hmmm veo que es vergonzoso, déjame profundizar más
Raphael en Digital Pianism
@KristjanH. ver mi actualización
Raphael en Digital Pianism
1
Usando <preferencia> ... es decir, lo que hice justo antes de escribir la pregunta aquí, sin embargo, no estoy contento con eso. Lo mismo con el uso de un complemento en addPageLayoutHandles, no quiero llamar a un complemento todo el tiempo, incluso si la penalización de rendimiento es inexistente, simplemente no es correcto. Veamos si aparecen otras soluciones aquí.
Kristjan H.
¿Intentaste otra forma después de esto?
LM_Fielding
8

Tuve un problema similar. para las categorías que no muestran listas de productos, necesitaba un identificador adicional. después de no poder agregar el identificador a través del XML de diseño personalizado de la categoría, terminé agregándolo en un observador en el layout_load_beforeevento:

class LayoutLoadBefore implements \Magento\Framework\Event\ObserverInterface
{
    /**
     * @var \Magento\Framework\Registry
     */
    protected $_registry;

    public function __construct(
        \Magento\Framework\Registry $registry
    )
    {
        $this->_registry = $registry;
    }

    /**
     * add a custom handle to categories of page type 'PAGE'
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return $this
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $action = $observer->getData('full_action_name');
        if ($action != 'catalog_category_view')
            return $this;

        $category = $this->_registry->registry('current_category');
        if (!$category)
            return $this;

        if ($category->getDisplayMode() == $category::DM_PAGE) {
            $layout = $observer->getData('layout');
            $layout->getUpdate()->addHandle('catalog_category_view_cms');
        }

        return $this;
    }
}

hay un pequeño impacto en el rendimiento involucrado ya que se llama al observador para cada visita a la página. desafortunadamente, todos los eventos relacionados con 'category_view' parecen ser demasiado pronto (categoría aún no cargada) o demasiado tarde (diseño ya procesado).

alternar
fuente
¡Gracias! Tuve un problema similar ( magento.stackexchange.com/questions/156231/… ) y un complemento \Magento\Cms\Controller\Page\View::execute()y \Magento\Framework\View\Result\Page::addPageLayoutHandles() or render()no funcionó. Esta solución de último recurso fue la única solución que funcionó para mí.
Giel Berkers
1

Intentemos observar el evento layout_load_before. La función de ejecución será la misma que esta:

public function execute(\Magento\Framework\Event\Observer $observer)
    {
        if($observer->getFullActionName() == 'catalog_category_view'){
            $observer->getLayout()->getUpdate()->addHandle('your_custom_handles');
        }
    }

Espero que esto ayude

Hồ Trung Nghĩa
fuente