Magento 2: Wie funktionieren Kundenbereiche / Abschnitte.xml?

49

Ich bin kürzlich auf ein neues Konzept in Magento 2 gestoßen, das ich interessant fand: Kundenbereiche

Einige von Ihnen haben möglicherweise das Vorhandensein von sections.xmlDateien bemerkt , die wie folgt aussehen:

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

Nach meinem Verständnis geben diese Dateien an, welche Kundenbereiche aktualisiert werden sollen, wenn die entsprechende Aktion aufgerufen wird.

Das ist mir zum Beispiel mit Magento/Checkout/etc/frontend/sections.xmlfolgendem Teil aufgefallen :

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

Löst das Minicart-Update aus, nachdem Sie ein Produkt in den Warenkorb gelegt haben.

Ich habe versucht, ein benutzerdefiniertes Modul mit der folgenden etc/frontend/sections.xmlDatei zu erstellen, um diese Funktion zu testen:

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

Es scheint jedoch nicht zu versuchen, meinen Warenkorbbereich zu aktualisieren, wenn ich die Warenkorbseite erreiche (keine GET-Anforderung in der Konsole). Es sieht so aus, als würde die Funktionalität des gesamten Abschnitts Magento_Customerin irgendeiner Weise vom Modul übernommen.

  • Was sind genau diese Abschnitte? Wie definieren Sie einen Abschnitt?
  • Wie werden die Abschnittsaktualisierungen ausgelöst?
  • (Optional) Wie kann ich meinen Testcode korrigieren, um das Minicart zu aktualisieren, wenn ich die Warenkorbseite erreiche?
Raphael bei Digital Pianism
quelle
Wird dies in der Steuerung ausgelöst und auf die verwiesen wird, z. B. durch eine Ausführungsmethode oder auf eine andere Weise?
LM_Fielding
1
@LM_Fielding siehe Ich habe gerade eine Antwort gepostet: magento.stackexchange.com/a/142350/2380
Raphael bei Digital Pianism

Antworten:

82

Was sind genau diese Abschnitte?

Ein Abschnitt ist ein Teil der Kundendaten, die zusammen gruppiert sind. Jeder Abschnitt wird durch einen Schlüssel dargestellt, mit dem auf Daten und Daten selbst zugegriffen und diese verwaltet werden. Magento lädt Abschnitte per AJAX-Anfrage /customer/section/load/und speichert geladene Daten im lokalen Speicher des Browsers unter dem Schlüssel zwischen mage-cache-storage. Magento verfolgt, wenn ein Abschnitt geändert wird, und lädt den aktualisierten Abschnitt automatisch.

Wie definieren Sie einen Abschnitt?

Ein Abschnitt, der in di.xmlDatei definiert wird, indem ein neuer Abschnitt in den Abschnittspool eingefügt wird

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

Hier sind also zwei neue Rubriken eingetragen cartund directory-data. Magento\Checkout\CustomerData\Cartund Magento\Checkout\CustomerData\DirectoryDataimplementiert Magento\Customer\CustomerData\SectionSourceInterfaceund liefert tatsächliche Daten als Ergebnis der getSectionDataMethode.

Wie werden die Abschnittsaktualisierungen ausgelöst?

Magento geht davon aus, dass die privaten Daten des Kunden geändert wird , wenn ein Kunde eine Zustandsänderungsanforderung sendet ( POST, PUT, DELETE). Um die Belastung des Servers zu minimieren, sollten Entwickler angeben, welche Aktion (oder Anforderung) welchen Kundendatenabschnitt in aktualisiert etc/section.xml.

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

Der Aktionsname ist ein Aktionsschlüsselmuster. Wenn ein Benutzer eine Aktion aufruft, die dem angegebenen Muster entspricht, erkennt Magento, dass der entsprechende Abschnitt veraltet ist, und lädt ihn erneut. Wenn der Aktionsname lautet *, bedeutet dies, dass der Abschnitt bei jeder POST- und PUT-Anforderung aktualisiert wird. Wenn das Abschnitts-Tag fehlt, werden alle Abschnitte aktualisiert.

Konzeptionell ist es also falsch, den Mini-Warenkorb zu aktualisieren, wenn Sie eine umfangreiche Warenkorbseite haben. Zu diesem Zeitpunkt sollte der Mini Cart (oder der Cart-Bereich) bereits aktualisiert sein.

Weitere Informationen zu Kundendaten finden Sie hier


Interne Implementierung

Um zu verstehen, wann und wie Abschnitte aktualisiert werden, sehen wir uns die Implementierung an. Der Schlüssel zum Verständnis sind Dateien magento2ce/app/code/Magento/Customer/view/frontend/web/js/section-config.jsund magento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js.

Am Ende des letzten Tages ist einer der beiden Event-Handler für ajaxCompleteund registriert submit. Das bedeutet , dass , wenn irgendeine Form geschrieben wird (mit POST oder PUT - Methoden) an dem Server, oder wenn JavaScript sendet einen AJAX, POSToder PUTWunsch werden die Handler aufgerufen. Beide Handler haben eine ähnliche Logik: Mit Hilfe von Magento_Customer/js/section-configcheck sollte jeder Abschnitt aktualisiert werden oder nicht. Wenn ein Abschnitt aktualisiert werden soll, customerData.invalidate(sections)wird aufgerufen. Und später werden alle ungültigen Abschnitte von einem Server geladen.

Woher Magento_Customer/js/section-configweiß man also , welcher Abschnitt entfernt werden soll und auf welche Aktion? Die Antwort ist in 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>

Auf diese Weise übergibt ein Server die Konfiguration zusammengeführter Abschnitte an einen Browser.

Unter der Annahme, dass dies alles der Fall ist , kann der Abschnitt nur durch POST- oder PUT-Formularübermittlung oder AJAX-Anforderung aktualisiert werden

Außerdem gibt es nur zwei Noten:

  • Alles, was hier beschrieben wird, ist eine interne Implementierung und kann geändert werden. Daher können Sie sicher nur die Datei section.xml verwenden und Abschnittsaktualisierungen erwarten, wenn bestimmte POST-, PUT- oder DELETE-Aktionen ausgelöst werden.
  • Wenn Sie sicher sind, dass Sie einen Abschnitt wirklich aktualisieren müssen, können Sie immer so etwas tun: require('Magento_Customer/js/customer-data').reload(['cart'], false)
Volodymyr Kublytskyi
quelle
Super danke dafür. Kannst du irgendwie sagen, warum der Code in meiner Frage den Mini-Warenkorb nicht aktualisiert, wenn ich die Warenkorbseite erreiche?
Raphael bei Digital Pianism
1
@ RaphaelatDigitalPianism, ich habe meinen Kommentar mit Antwort aktualisiert
Volodymyr Kublytskyi
Ich führe einen benutzerdefinierten Ajax-Aufruf auf der Warenkorbseite durch. Ich benötige diesen Aufruf der Kundenladesektion nicht. Wie kann ich das vermeiden? magento.stackexchange.com/questions/156425/…
seeni
5

Aktion, die Sie im Tag definiert haben, sollte über die POST-Anforderung ausgelöst werden. z.B:

Auch wenn Sie Kundendaten in allen Bereichen aktualisieren möchten, verwenden Sie einfach (siehe Hersteller / magento / module-customer / etc / frontend / areas.xml).

Sie können auch am Ende der Datei nachsehen. vendor/magento/module-customer/view/frontend/web/js/section-‌​config.js
Finden Sie den Code:

$ (document) .on ('submit', function (event) { 
    var Abschnitte; 
    if (event.target.method.match (/ post | put / i)) { 
        Abschnitte = sectionConfig.getAffectedSections (event.target.action);
        if (Abschnitte) { 
            customerData.invalidate (Abschnitte); 
        } 
    } 
});
lemk0
quelle
Sie können auch das Ende der Datei vendor / magento / module-customer / view / frontend / web / js / section-config.js anzeigen. Suchen Sie den Code $ (document) .on ('submit', function (event) {var Abschnitte; if (event.target.method.match (/ post | put / i)) {Abschnitte = sectionConfig.getAffectedSections (event.target.action); if (Abschnitte) {customerData.invalidate (Abschnitte);}}) ;
Lemk0
3

Ein hackiger Weg, den ich gefunden habe:

In meiner Action-Klasse, die zum Einkaufswagen umleitet, mache ich Folgendes:

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

Dann habe ich Folgendes zu meiner Warenkorb-Seite hinzugefügt:

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

Dann habe ich in meinem Block:

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

Und meine Refresh.phpActionklasse sieht so aus:

<?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 bei Digital Pianism
quelle
Raphael, meine section.xml versucht nicht einmal, den Warenkorb zu aktualisieren, wenn ich eine Post-Anfrage an die URL in der Datei sende ... Irgendwelche Ideen?
LM_Fielding
@LM_Fielding Ja, ich hatte die gleichen Leute, lies meine Antwort
Raphael bei Digital Pianism
Also, um es zum Laufen zu bringen, müssen wir das schreiben? Ist das Standardverhalten fehlerhaft oder missverstehe ich es?
LM_Fielding
@LM_Fielding Nun, ich weiß nicht, warum ich diese Frage gestellt habe und ich habe keine gute Antwort darauf bekommen. Wie gesagt, das ist die "hackige" Art, wie ich es gefunden habe.
Raphael bei Digital Pianism
Es wurde definitiv eine relative URL für mich verwendet - es löst nicht die Abschnittsaktualisierung aus.
LM_Fielding
0

Ich habe das gleiche Problem wie der Fragesteller. Nach ein paar Stunden Recherche und Durchforsten der Dokumentation und des Kerncodes bekam ich plötzlich eine Lösung. In meinem Fall habe ich ... / etc / frontend / areas.xml Datei mit

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

Und es wollte nicht funktionieren. Nachdem ich dieses Thema und diese Ausgabe https://github.com/magento/magento2/issues/3287 gelesen hatte, war ich so verwirrt, dass ich anfing zu experimentieren. Für mich hilft das Hinzufügen von Schrägstrichen:

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

Hoffe, es wird jemandem helfen, weniger Zeit für die Lösungsfindung zu verwenden.

Alex Kozyr
quelle