Magento 2: comment fonctionnent les sections client / sections.xml?

50

J'ai récemment découvert un nouveau concept intéressant dans Magento 2: les sections client

Certains d'entre vous ont peut-être remarqué la présence de sections.xmlfichiers ressemblant à ceci:

<?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>

D'après ce que j'ai compris, ces fichiers spécifient quelles sections du client doivent être mises à jour lorsque l'action correspondante est appelée.

J'ai remarqué par exemple avec la Magento/Checkout/etc/frontend/sections.xmlpartie suivante:

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

C’est ce qui déclenche la mise à jour minicart après avoir ajouté un produit au panier.

J'ai essayé de créer un module personnalisé avec le etc/frontend/sections.xmlfichier suivant pour tester cette fonctionnalité:

<?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>

Mais il ne semble pas essayer de mettre à jour la section de mon panier lorsque j'atteins la page du panier (aucune demande GET dans la console). Il semble que toute cette fonctionnalité de section soit gérée par le Magento_Customermodule d’une manière ou d’une autre.

  • Quelles sont exactement ces sections? Comment définissez-vous une section?
  • Comment les mises à jour de section sont-elles déclenchées?
  • (Facultatif) Comment puis-je corriger mon code de test pour mettre à jour le minicart lorsque j'atteins la page du panier?
Raphael au pianisme numérique
la source
Est-ce que cela est déclenché dans le contrôleur et l'action référencée, par exemple par une méthode execute ou par un autre moyen?
LM_Fielding
1
@LM_Fielding see Je viens de poster une réponse: magento.stackexchange.com/a/142350/2380
Raphael au Digital Pianism

Réponses:

84

Quelles sont exactement ces sections?

Une section est une donnée client regroupée. Chaque section est représentée par une clé utilisée pour accéder aux données et les gérer elles-mêmes. Magento charge les sections par requête AJAX /customer/section/load/et met en cache les données chargées dans la mémoire de stockage locale du navigateur, sous la clé mage-cache-storage. Magento assure le suivi du changement de section et le chargement de la section mise à jour automatiquement.

Comment définissez-vous une section?

Une section définie dans un di.xmlfichier en ajoutant une nouvelle section au pool de sections

<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>

Donc ici deux nouvelles sections sont enregistrées cartet directory-data. Magento\Checkout\CustomerData\Cartet Magento\Checkout\CustomerData\DirectoryDataimplémente Magento\Customer\CustomerData\SectionSourceInterfaceet fournit les données réelles en tant que résultat de la getSectionDataméthode.

Comment les mises à jour de section sont-elles déclenchées?

Magento suppose que lorsqu'un client envoie une demande de modification d'état est changé les données privées du client ( POST, PUT, DELETE). Pour minimiser la charge sur le serveur, les développeurs doivent spécifier quelle action (ou demande) met à jour la section de données client de etc/section.xml.

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

Le nom de l'action est un modèle de clé d'action. Lorsqu'un utilisateur appelle une action correspondant au modèle spécifié, Magento détectera cette section et la rechargera. Si nom de l'action est *défini, cela signifie que cette section sera mise à jour à chaque demande POST et PUT. Si la balise de section est manquée, toutes les sections seront mises à jour.

Donc, conceptuellement, il est faux de mettre à jour le mini-panier lorsque vous utilisez une page de panier riche. À ce stade, le mini-panier (ou la section du panier) devrait déjà être mis à jour.

Vous pouvez trouver plus d'informations sur les données client ici


Mise en œuvre interne

Pour comprendre quand et comment les sections sont mises à jour, voyons l'implémentation. Les fichiers magento2ce/app/code/Magento/Customer/view/frontend/web/js/section-config.jset magento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js.

À la fin du dernier des deux événements, les gestionnaires sont enregistrés pour ajaxCompleteet submit. Cela signifie que lorsqu'un formulaire est posté (avec des méthodes POST ou PUT) sur le serveur, ou que JavaScript envoie une AJAX, POSTou une PUTdemande, les gestionnaires sont appelés. Les deux gestionnaires ont une logique similaire: avec l'aide de Magento_Customer/js/section-configcheck, toute section doit être mise à jour ou non. Si une section doit être mise à jour, elle customerData.invalidate(sections)est appelée. Et plus tard, toutes les sections invalidées sont chargées depuis un serveur.

Alors, comment Magento_Customer/js/section-configsavoir quelle section doit être supprimée et pour quelle action? La réponse est dans 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 cette manière, un serveur transmet la configuration des sections fusionnées à un navigateur.

Donc, en supposant que tout cela, section peut être mise à jour uniquement par la soumission de formulaire POST ou PUT ou demande AJAX

De plus, il n'y a que deux notes:

  • Tout ce qui est décrit ici est une implémentation interne et peut être modifié. Vous pouvez donc utiliser en toute sécurité uniquement sections.xml et attendre des mises à jour de section lorsque des actions POST, PUT ou DELETE spécifiées sont déclenchées.
  • si vous êtes sûr que vous avez vraiment besoin de mettre à jour une section, vous pouvez toujours faire quelque chose comme ceci: require('Magento_Customer/js/customer-data').reload(['cart'], false)
Volodymyr Kublytskyi
la source
Super merci pour ça. De toute façon, vous pouvez dire pourquoi le code dans ma question ne rafraîchit pas le mini-panier lorsque j'atteins la page du panier?
Raphael au pianisme numérique
1
@RaphaelatDigitalPianism, j'ai mis à jour mon commentaire avec la réponse
Volodymyr Kublytskyi
Je fais un appel ajax personnalisé dans la page panier, je n'ai pas besoin de cet appel de section de chargement client. Comment puis-je éviter ça? magento.stackexchange.com/questions/156425/…
seeni
5

L'action que vous avez définie dans la balise doit être évoquée via une requête POST. par exemple:

De même, si vous souhaitez actualiser les données client dans toutes les sections, utilisez simplement (consultez le site / fournisseur / module-client / etc / frontend / sections.xml du module).

Vous pouvez aussi regarder à la fin du fichier vendor/magento/module-customer/view/frontend/web/js/section-‌​config.js
Trouver le code:

$ (document) .on ('submit', fonction (événement) { 
    sections var; 
    if (event.target.method.match (/ post | put / i)) { 
        sections = sectionConfig.getAffectedSections (event.target.action);
        si (sections) { 
            customerData.invalidate (sections); 
        } 
    } 
});
lemk0
la source
Vous pouvez également consulter la fin du fichier vendeur / magento / module-client / vue / frontend / web / js / section-config.js. Trouver le code $ (document) .on ('submit', function (event) {var sections; if (événement.target.method.match (/ post | put / i)) {sections = sectionConfig.getAffectedSections (event.target.action); if (sections) {customerData.invalidate (sections);}}}) ;
lemk0
3

Une façon hacky que j'ai trouvée pour faire ça:

Dans ma classe d'action qui redirige vers le panier, je fais:

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

Ensuite, j'ai ajouté ce qui suit à ma page de panier:

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

Puis dans mon bloc j'ai:

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');
}

Et ma Refresh.phpclasse d'action ressemble à ceci:

<?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 au pianisme numérique
la source
Raphael, mon fichier sections.xml n'essaie même pas de mettre à jour le panier lorsque j'envoie une demande de publication à l'URL du fichier ... Des idées?
LM_Fielding
@LM_Fielding oui j'ai eu les mêmes personnes, lisez ma réponse
Raphael au Digital Pianism
Donc, pour que cela fonctionne, nous devons écrire ceci? Le comportement par défaut est-il rompu ou suis-je mal compris?
LM_Fielding
@LM_Fielding bien je ne sais pas c'est pourquoi j'ai posé cette question et je n'ai pas eu de bonne réponse à ce sujet. Comme je l’ai dit, c’est la méthode "simpliste" que j’ai trouvée pour le faire.
Raphael au pianisme numérique
Il utilisait certainement une URL relative pour moi - cela ne déclenche pas la mise à jour de la section.
LM_Fielding
0

J'ai rencontré le même problème que l'auteur de la question. Après quelques heures de recherche et de manipulation de la documentation et du code principal, j'ai soudain eu la solution. Dans mon cas, j'ai ... le fichier / etc / frontend / sections.xml avec

<?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>

Et ça ne voulait pas marcher. Après avoir lu ce sujet et ce problème https://github.com/magento/magento2/issues/3287, j'étais tellement confus que j'ai commencé à expérimenter. Pour moi, aide en ajoutant des barres obliques:

 <?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>

J'espère que cela aidera quelqu'un à passer moins de temps à trouver une solution.

Alex Kozyr
la source