Magento 2: jak działają sekcje / sekcje klienta.xml?

49

Niedawno natknąłem się na nową koncepcję Magento 2, która mnie zainteresowała: sekcje dla klientów

Niektórzy z was mogą zauważyć obecność sections.xmlplików, które wyglądają tak:

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

Z tego, co zrozumiałem, pliki te określają, które sekcje klientów powinny zostać zaktualizowane po wywołaniu odpowiedniej akcji.

Zauważyłem na przykład Magento/Checkout/etc/frontend/sections.xmlnastępującą część:

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

To właśnie powoduje aktualizację minicart po dodaniu produktu do koszyka.

Próbowałem utworzyć niestandardowy moduł z następującym etc/frontend/sections.xmlplikiem, aby przetestować tę funkcję:

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

Ale nie wydaje się, aby próbować zaktualizować sekcję koszyka, gdy dojdę do strony koszyka (brak żądania GET w konsoli). Wygląda na to, że Magento_Customermoduł w jakiś sposób obsługuje całą tę sekcję .

  • Czym dokładnie są te sekcje? Jak definiujesz sekcję?
  • W jaki sposób uruchamiane są aktualizacje sekcji?
  • (Opcjonalnie) Jak mogę naprawić kod testowy, aby zaktualizować minikart po przejściu na stronę koszyka?
Raphael at Digital Pianism
źródło
Czy jest to wyzwalane w kontrolerze i przywołanej akcji, takiej jak metoda wykonania lub w inny sposób?
LM_Fielding
1
@LM_Fielding zobacz, że właśnie opublikowałem odpowiedź: magento.stackexchange.com/a/142350/2380
Raphael at Digital Pianism 24.10.16

Odpowiedzi:

82

Czym dokładnie są te sekcje?

Sekcja to zgrupowane dane klienta. Każda sekcja jest reprezentowana przez klucz, który służy do uzyskiwania dostępu do danych i zarządzania nimi. Magento ładuje sekcje według żądania AJAX /customer/section/load/i buforuje załadowane dane w lokalnej pamięci przeglądarki pod kluczem mage-cache-storage. Magento śledzi zmiany niektórych sekcji i automatycznie ładuje zaktualizowane sekcje.

Jak definiujesz sekcję?

Sekcja zdefiniowana w di.xmlpliku przez dodanie nowej sekcji do puli sekcji

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

Więc tutaj zarejestrowane są dwie nowe sekcje carti directory-data. Magento\Checkout\CustomerData\Cartoraz Magento\Checkout\CustomerData\DirectoryDatawdraża Magento\Customer\CustomerData\SectionSourceInterfacei dostarcza rzeczywiste dane w wyniku getSectionDatametody.

W jaki sposób uruchamiane są aktualizacje sekcji?

Magento zakłada, że prywatne dane klienta ulega zmianie, gdy klient wysyła żądanie modyfikacji jakiś stan ( POST, PUT, DELETE). Aby zminimalizować obciążenie serwera, programiści powinni określić, które działanie (lub żądanie) aktualizuje sekcję danych klienta etc/section.xml.

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

Nazwa akcji to wzór klucza akcji. Gdy użytkownik wezwie do działania pasującego do określonego wzorca, Magento wykryje, że odpowiednia sekcja jest nieaktualna i załaduje ją ponownie. Jeśli nazwa akcji to *oznacza, że ​​sekcja będzie aktualizowana przy każdym żądaniu POST i PUT. Jeśli tag sekcji zostanie pominięty, wszystkie sekcje zostaną zaktualizowane.

Więc koncepcyjnie źle jest aktualizować mini koszyk, gdy strona z bogatym koszykiem jest. W tym momencie mini koszyk (lub sekcja koszyka) powinien już zostać zaktualizowany.

Więcej informacji o danych klientów można znaleźć tutaj


Wdrożenie wewnętrzne

Aby zrozumieć, kiedy i jak sekcje są aktualizowane, zobaczmy implementację. Kluczem do zrozumienia są pliki magento2ce/app/code/Magento/Customer/view/frontend/web/js/section-config.jsi magento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js.

Na koniec ostatniego z dwóch zarejestrowanych programów obsługi zdarzeń dla ajaxCompletei submit. Oznacza to, że gdy każda forma jest zamieszczona (z metody POST lub PUT) do serwera lub gdy JavaScript wysyła AJAX, POSTlub PUTwniosek, koparki zostanie wywołany. Oba programy obsługi mają podobną logikę: przy pomocy Magento_Customer/js/section-configsprawdzania należy zaktualizować dowolną sekcję. Jeśli jakaś sekcja powinna zostać zaktualizowana, wówczas customerData.invalidate(sections)jest wywoływana. A później wszystkie unieważnione sekcje są ładowane z serwera.

Magento_Customer/js/section-configSkąd więc wiadomo, którą sekcję należy usunąć i na której akcji? Odpowiedź jest w 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>

W ten sposób serwer przekazuje konfigurację scalonych sekcji do przeglądarki.

Zakładając, że wszystko to, sekcja może być aktualizowana tylko przez przesłanie formularza POST lub PUT lub żądanie AJAX

Ponadto istnieją tylko dwie notatki:

  • wszystko tutaj opisane jest implementacją wewnętrzną i może być zmienione, więc możesz bezpiecznie używać tylko section.xml i oczekiwać aktualizacji sekcji, gdy zostaną uruchomione określone działania POST lub PUT lub DELETE.
  • jeśli jesteś pewien, że naprawdę potrzebujesz zaktualizować jakąś sekcję, zawsze możesz zrobić coś takiego: require('Magento_Customer/js/customer-data').reload(['cart'], false)
Włodzimierz Kubłytskij
źródło
Niesamowite dzięki za to. W jakikolwiek sposób możesz powiedzieć, dlaczego kod w moim pytaniu nie odświeża mini-koszyka, gdy wchodzę na stronę koszyka?
Raphael at Digital Pianism
1
@RaphaelatDigitalPianism, zaktualizowałem swój komentarz odpowiedzią
Volodymyr Kublytskyi
Wykonuję niestandardowe wywołanie strony ajax w koszyku, nie potrzebuję tego wywołania sekcji ładowania klienta. Jak mogę tego uniknąć? magento.stackexchange.com/questions/156425/…
seeni
5

Czynność zdefiniowana w tagu powinna zostać wywołana przez żądanie POST. na przykład:

Również jeśli chcesz odświeżyć dane klienta we wszystkich sekcjach, po prostu użyj (Spójrz na dostawcę / magento / module-customer / etc / frontend / section.xml)

Możesz także spojrzeć na koniec pliku vendor/magento/module-customer/view/frontend/web/js/section-‌​config.js
Znajdź kod:

$ (dokument) .on („prześlij”, funkcja (zdarzenie) { 
    sekcje var; 
    if (event.target.method.match (/ post | put / i)) { 
        section = sectionConfig.getAffectedSections (event.target.action);
        if (sekcje) { 
            customerData.invalidate (sekcje); 
        } 
    } 
});
lemk0
źródło
Możesz także spojrzeć na koniec dostawcy pliku / magento / module-customer / view / frontend / web / js / section-config.js Znajdź kod $ (dokument) .on ('zgłoś', funkcja (zdarzenie) {var sekcje; if (event.target.method.match (/ post | put / i)) {sekcje = sectionConfig.getAffectedSections (event.target.action); if (sekcje) {customerData.invalidate (sekcje);}}}) ;
lemk0
3

Hacky sposób, w jaki znalazłem to zrobić:

W mojej klasie akcji, która przekierowuje do koszyka, robię:

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

Następnie dodałem następujące elementy do mojej strony koszyka:

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

Następnie w moim bloku mam:

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

A moja Refresh.phpklasa akcji wygląda następująco:

<?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 at Digital Pianism
źródło
Raphael, moje sekcje.xml nawet nie próbują aktualizować koszyka, kiedy wysyłam żądanie do adresu URL w pliku ... Jakieś pomysły?
LM_Fielding 24.10.16
@LM_Fielding tak Miałem tych samych ludzi, przeczytaj moją odpowiedź
Raphael w Digital Pianism
Więc żeby to zadziałało, musimy to napisać? Czy domyślne zachowanie jest zepsute, czy też nieporozumienie?
LM_Fielding
@LM_Fielding dobrze Nie wiem, dlatego zadałem to pytanie i nie otrzymałem żadnej dobrej odpowiedzi na ten temat. Jak powiedziałem, jest to „hacky” sposób, w jaki to zrobiłem.
Raphael w Digital Pianism
Zdecydowanie używał dla mnie względnego adresu URL - nie uruchamia aktualizacji sekcji.
LM_Fielding 24.10.16
0

Napotkałem ten sam problem co autor pytania. Po kilku godzinach poszukiwań i analizowania dokumentacji i podstawowego kodu nagle znalazłem rozwiązanie. W moim przypadku mam plik ... / etc / frontend / section.xml z

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

I nie chciał działać. Po przeczytaniu tego tematu i tego problemu https://github.com/magento/magento2/issues/3287 byłem tak zdezorientowany, że zacząłem eksperymentować. Dla mnie pomaga dodawanie ukośników:

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

Mam nadzieję, że pomoże to komuś poświęcić mniej czasu na znalezienie rozwiązania.

Alex Kozyr
źródło