Magento 2: ¿como funcionan las secciones de cliente / secciones.xml?

49

Recientemente me encontré con un nuevo concepto en Magento 2 que me pareció interesante: secciones de clientes

Algunos de ustedes pueden haber notado la presencia de sections.xmlarchivos que se ven así:

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="sales/guest/reorder">
        <section name="cart"/>
    </action>
    <action name="sales/order/reorder">
        <section name="cart"/>
    </action>
</config>

Por lo que entendí, esos archivos especifican qué secciones del cliente deben actualizarse cuando se llama a la acción correspondiente.

Me di cuenta por ejemplo con Magento/Checkout/etc/frontend/sections.xmlla siguiente parte:

<action name="checkout/cart/add">
    <section name="cart"/>
</action>

Es lo que desencadena la actualización de minicart después de haber agregado un producto al carrito.

Intenté crear un módulo personalizado con el siguiente etc/frontend/sections.xmlarchivo para probar esa característica:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="checkout/cart/index">
        <section name="cart"/>
    </action>
</config>

Pero no parece intentar actualizar la sección de mi carrito cuando llego a la página del carrito (no hay solicitud GET en la consola). Parece que toda la funcionalidad de esta sección es manejada por el Magento_Customermódulo de alguna manera.

  • ¿Qué son exactamente esas secciones? ¿Cómo se define una sección?
  • ¿Cómo se activan las actualizaciones de la sección?
  • (Opcional) ¿Cómo puedo corregir mi código de prueba para actualizar el minicart cuando llegue a la página del carrito?
Raphael en Digital Pianism
fuente
¿Se activa esto en el controlador y la acción a la que se hace referencia, como por un método de ejecución o de alguna otra manera?
LM_Fielding
1
@LM_Fielding ver Acabo de publicar una respuesta: magento.stackexchange.com/a/142350/2380
Raphael en Digital Pianism

Respuestas:

83

¿Qué son exactamente esas secciones?

Una sección es una pieza de datos del cliente agrupada. Cada sección está representada por una clave que se utiliza para acceder y administrar datos y datos en sí. Magento carga secciones por solicitud AJAX /customer/section/load/y almacena en caché los datos cargados en el almacenamiento local del navegador bajo la clave mage-cache-storage. Magento rastrea cuando se cambia alguna sección y carga la sección actualizada automáticamente.

¿Cómo se define una sección?

Una sección definida en el di.xmlarchivo al agregar una nueva sección al grupo de secciones

<type name="Magento\Customer\CustomerData\SectionPoolInterface">
    <arguments>
        <argument name="sectionSourceMap" xsi:type="array">
            <item name="cart" xsi:type="string">Magento\Checkout\CustomerData\Cart</item>
            <item name="directory-data" xsi:type="string">Magento\Checkout\CustomerData\DirectoryData</item>
        </argument>
    </arguments>
</type>

Así que aquí están registradas dos nuevas secciones carty directory-data. Magento\Checkout\CustomerData\Carty Magento\Checkout\CustomerData\DirectoryDataimplementos Magento\Customer\CustomerData\SectionSourceInterfacey proporciona datos reales como resultado de getSectionDatamétodo.

¿Cómo se activan las actualizaciones de la sección?

Magento supone que los datos privados del cliente se cambia cuando un cliente envía alguna solicitud de modificación del estado ( POST, PUT, DELETE). Para minimizar la carga en el servidor, los desarrolladores deben especificar qué acción (o solicitud) actualiza en qué sección de datos del cliente etc/section.xml.

<action name="checkout/cart/add">
    <section name="cart"/>
</action>

El nombre de la acción es un patrón de clave de acción. Cuando un usuario llama a la acción que coincide con el patrón especificado, Magento detectará que la sección correspondiente está desactualizada y la cargará nuevamente. Si el nombre de la acción es *eso significa que esa sección se actualizará en cada solicitud POST y PUT. Si se pierde la etiqueta de sección, se actualizará toda la sección.

Conceptualmente, esto es incorrecto para actualizar el mini carrito cuando haces una página de carrito enriquecido. En este punto, el mini carrito (o sección del carrito) ya debería estar actualizado.

Puede encontrar más información sobre los datos del cliente aquí


Implementación interna

Para entender cuándo y cómo se actualizan las secciones, veamos la implementación. La clave para entender son los archivos magento2ce/app/code/Magento/Customer/view/frontend/web/js/section-config.jsy magento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js.

Al final del último de los dos controladores de eventos están registrados para ajaxCompletey submit. Eso significa que cuando se registró ninguna forma (con POST o PUT métodos) al servidor, o cuando envía un JavaScript AJAX, POSTo PUTpetición, se invocarán los manipuladores. Ambos manejadores tienen una lógica similar: con la ayuda de Magento_Customer/js/section-configcheck debería haber cualquier sección actualizada o no. Si alguna sección debe actualizarse, customerData.invalidate(sections)se llama. Y más tarde, todas las secciones invalidadas se cargan desde un servidor.

Entonces, ¿cómo Magento_Customer/js/section-configsaber qué sección debe eliminarse y en qué acción? La respuesta está en Magento/Customer/view/frontend/templates/js/section-config.phtml:

<script type="text/x-magento-init">
<?php
     /* @noEscape */ echo $this->helper(\Magento\Framework\Json\Helper\Data::class)->jsonEncode([
    '*' => ['Magento_Customer/js/section-config' => [
        'sections' => $block->getSections(),
        'clientSideSections' => $block->getClientSideSections(),
        'baseUrls' => array_unique([
            $block->getUrl(null, ['_secure' => true]),
            $block->getUrl(null, ['_secure' => false]),
        ]),
    ]],
]);
?>
</script>

De esta manera, un servidor pasa la configuración de secciones fusionadas a un navegador.

Asumiendo todo eso, la sección puede actualizarse solo mediante el envío de un formulario POST o PUT o una solicitud AJAX

Además, solo hay dos notas:

  • todo lo que se describe aquí es una implementación interna y puede modificarse, por lo que puede usar con seguridad solo secciones.xml y esperar actualizaciones de la sección cuando se activen acciones POST o PUT o DELETE especificadas.
  • si está seguro de que realmente necesita actualizar alguna sección, siempre puede hacer algo como esto: require('Magento_Customer/js/customer-data').reload(['cart'], false)
Volodymyr Kublytskyi
fuente
Impresionante gracias por eso. ¿De alguna manera puedes decir por qué el código en mi pregunta no actualiza el mini carrito cuando llego a la página del carrito?
Raphael en Digital Pianism
1
@RaphaelatDigitalPianism, he actualizado mi comentario con respuesta
Volodymyr Kublytskyi
Estoy haciendo una llamada ajax personalizada en la página del carrito, no necesito esta llamada a la sección de carga del cliente. ¿Cómo puedo evitar esto? magento.stackexchange.com/questions/156425/…
seeni
5

La acción que definió en la etiqueta debe evocarse mediante la solicitud POST. p.ej:

Además, si desea actualizar los datos del cliente en todas las secciones, simplemente use (Consulte vendor / magento / module-customer / etc / frontend / secciones.xml)

También puedes mirar al final del archivo vendor/magento/module-customer/view/frontend/web/js/section-‌​config.js
Encuentra el código:

$ (document) .on ('submit', function (event) { 
    secciones var; 
    if (event.target.method.match (/ post | put / i)) { 
        secciones = sectionConfig.getAffectedSections (event.target.action);
        if (secciones) { 
            customerData.invalidate (secciones); 
        } 
    } 
});
lemk0
fuente
También puede ver el final del archivo vendor / magento / module-customer / view / frontend / web / js / section-config.js Encuentre el código $ (document) .on ('submit', function (event) {var secciones; if (event.target.method.match (/ post | put / i)) {secciones = sectionConfig.getAffectedSections (event.target.action); if (secciones) {customerData.invalidate (secciones);}}}) ;
lemk0
3

Una forma hacky que encontré para hacer eso:

En mi clase de acción que redirige al carrito que hago:

$this->_checkoutSession->setMinicartNeedsRefresh(true);

Luego agregué lo siguiente a mi página de carrito:

<?php if ($this->isRefreshRequired()): ?>
    <script type="text/javascript">
        require( [ 'jquery' ], function ($)
        {
            $.ajax({
                url: '<?php echo $this->getRefreshUrl(); ?>',
                type: 'POST'
            });
        });
    </script>
<?php endif; ?>

Entonces en mi bloque tengo:

public function isRefreshRequired()
{
    if ($this->_checkoutSession->getMinicartNeedsRefresh()) {
        $this->_checkoutSession->setMinicartNeedsRefresh(false);
        return true;
    } else {
        return false;
    }
}

/**
 * Get the refresh URL
 * @return string
 */
public function getRefreshUrl()
{
    return $this->getUrl('module/cart/refresh');
}

Y mi Refresh.phpclase de acción se ve así:

<?php

namespace Vendor\Module\Controller\Cart;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

class Refresh extends Action
{

    /**
     * Dummy action class called via AJAX to trigger the section update
     */
    public function execute()
    {
        return $this->getResponse()->representJson(
            $this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode(['success'=>true])
        );
    }
}
Raphael en Digital Pianism
fuente
Raphael, mi section.xml ni siquiera está intentando actualizar el carrito cuando envío una solicitud de publicación a la url en el archivo ... ¿Alguna idea?
LM_Fielding
@LM_Fielding sí, tenía la misma gente, lee mi respuesta
Raphael en Digital Pianism el
Entonces, para que funcione, tenemos que escribir esto. ¿El comportamiento predeterminado está roto o estoy malentendido?
LM_Fielding
@LM_Fielding bien No sé por eso hice esta pregunta y no obtuve ninguna buena respuesta al respecto. Como dije, esta es la forma "hacky" que encontré para hacerlo.
Raphael en Digital Pianism
Definitivamente estaba usando una URL relativa para mí, no activa la actualización de la sección.
LM_Fielding
0

Me he enfrentado al mismo problema que el autor de la pregunta. Después de algunas horas de investigación y análisis de documentación y código central, de repente obtuve una solución. En mi caso obtuve el archivo ... / etc / frontend / secciones.xml con

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="roadsignconf/index/addtocart">
        <section name="cart"/>
    </action>
</config>

Y no quería trabajar. Después de leer este tema y este problema https://github.com/magento/magento2/issues/3287, estaba tan confundido que comencé a experimentar. Para mí ayuda a agregar barras:

 <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
        <action name="/roadsignconf/index/addtocart/">
            <section name="cart"/>
        </action>
    </config>

Espero que ayude a alguien a pasar menos tiempo para encontrar una solución.

Alex Kozyr
fuente