Magento 2: как работают клиентские секции / section.xml?

50

Недавно я познакомился с новой концепцией в Magento 2, которая показалась мне интересной: разделы для клиентов

Некоторые из вас могут заметить наличие sections.xmlфайлов, которые выглядят так:

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

Из того, что я понял, эти файлы указывают, какие разделы клиента должны обновляться при вызове соответствующего действия.

Я заметил, например, со Magento/Checkout/etc/frontend/sections.xmlследующей частью:

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

Это то, что запускает обновление миникарты после того, как вы добавили товар в корзину.

Я попытался создать пользовательский модуль со следующим etc/frontend/sections.xmlфайлом для проверки этой функции:

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

Но, похоже, он не пытается обновить мой раздел корзины, когда я попадаю на страницу корзины (нет запроса GET в консоли). Кажется, что вся эта функциональность раздела Magento_Customerкаким-то образом обрабатывается модулем.

  • Что именно эти разделы? Как вы определяете раздел?
  • Как запускаются обновления раздела?
  • (Необязательно) Как я могу исправить свой тестовый код для обновления мини-карты, когда я попадаю на страницу корзины?
Рафаэль в цифровом пианизме
источник
Это вызвано в контроллере и на действие, на которое ссылаются, например, методом execute или каким-либо другим способом?
LM_Fielding
1
@LM_Fielding посмотри, что я только что опубликовал ответ: magento.stackexchange.com/a/142350/2380
Рафаэль на Digital Pianism

Ответы:

84

Что именно эти разделы?

Раздел - это часть данных клиента, сгруппированных вместе. Каждый раздел представлен ключом, который используется для доступа и управления данными и самими данными. Magento загружает разделы по запросу AJAX /customer/section/load/и кэширует загруженные данные в локальном хранилище браузера под ключом mage-cache-storage. Magento отслеживает изменение какого-либо раздела и автоматически загружает обновленный раздел.

Как вы определяете раздел?

Раздел, определенный в di.xmlфайле путем добавления нового раздела в пул разделов

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

Таким образом , здесь два новых раздела регистрируются cartи directory-data. Magento\Checkout\CustomerData\Cartи Magento\Checkout\CustomerData\DirectoryDataреализует Magento\Customer\CustomerData\SectionSourceInterfaceи предоставляет фактические данные как результат getSectionDataметода.

Как запускаются обновления раздела?

Magento предполагает , что личные данные клиента изменяется , когда клиент отправляет запрос на некоторое состояние модификации ( POST, PUT, DELETE). Чтобы свести к минимуму нагрузку на сервер, разработчики должны указать, какое действие (или запрос) обновляет какой раздел данных клиента etc/section.xml.

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

Имя действия - это шаблон ключа действия. Когда пользователь вызывает действие, соответствующее указанному шаблону, Magento обнаружит, что соответствующий раздел устарел, и снова загрузит его. Если имя действия *означает, что раздел будет обновляться при каждом запросе POST и PUT. Если тег раздела пропущен, то весь раздел будет обновлен.

Поэтому концептуально неправильно обновлять мини-корзину, когда вы загружаете страницу корзины. На этом этапе мини-корзина (или раздел корзины) уже должна быть обновлена.

Вы можете найти больше информации о данных клиента здесь


Внутренняя реализация

Чтобы понять, когда и как обновляются разделы, посмотрим реализацию. Ключом к пониманию являются файлы magento2ce/app/code/Magento/Customer/view/frontend/web/js/section-config.jsи magento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js.

В конце последнего один из двух обработчиков событий регистрируется для ajaxCompleteи submit. Это означает , что , когда любая форма размещена (с POST или методов PUT) к серверу, или когда JavaScript посылает AJAX, POSTили PUTзапрос, обработчики будут вызываться. Оба обработчика имеют схожую логику: с помощью Magento_Customer/js/section-configпроверки должен обновляться любой раздел или нет. Если какой-то раздел должен быть обновлен, то customerData.invalidate(sections)называется. И позже все недействительные разделы загружаются с сервера.

Итак, как Magento_Customer/js/section-configузнать, какой раздел должен быть удален и какое действие? Ответ в 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>

Таким образом, сервер передает конфигурацию объединенных секций в браузер.

Таким образом, при условии всего этого, раздел может быть обновлен только путем отправки формы POST или PUT или запроса AJAX.

Кроме того, есть только две заметки:

  • все, что здесь описано, является внутренней реализацией и может быть изменено, так что вы можете безопасно использовать только section.xml и ожидать обновления раздела, когда инициируются указанные действия POST или PUT или DELETE.
  • если вы уверены, что вам действительно нужно обновить какой-то раздел, вы всегда можете сделать что-то вроде этого: require('Magento_Customer/js/customer-data').reload(['cart'], false)
Владимир Кублицкий
источник
Огромное спасибо за это. В любом случае, вы можете сказать, почему код в моем вопросе не обновляет мини-корзину, когда я попадаю на страницу корзины?
Рафаэль на цифровом пианизме
1
@RaphaelatDigitalPianism, я обновил свой комментарий ответом
Владимир Кублицкий,
Я делаю пользовательский вызов ajax на странице корзины, мне не нужен этот вызов в разделе загрузки клиентов. Как я могу избежать этого? magento.stackexchange.com/questions/156425/…
видел
5

Действие, которое вы определили в теге, должно вызываться через запрос POST. например:

Также, если вы хотите обновить данные клиентов во всех разделах, просто используйте (посмотрите на vendor / magento / module-customer / etc / frontend / section.xml)

Вы также можете посмотреть в конце файла. vendor/magento/module-customer/view/frontend/web/js/section-‌​config.js
Найдите код:

$ (document) .on ('submit', function (event) { 
    вар разделы; 
    if (event.target.method.match (/ post | put / i)) { 
        section = sectionConfig.getActedSections (event.target.action);
        if (разделы) { 
            customerData.invalidate (секции); 
        } 
    } 
});
lemk0
источник
Вы также можете посмотреть конец файла vendor / magento / module-customer / view / frontend / web / js / section-config.js Найти код $ (document) .on ('submit', function (event) {var разделы; if (event.target.method.match (/ post | put / i)) {section = sectionConfig.getActedSections (event.target.action); if (section) {customerData.invalidate (section);}}}) ;
lemk0
3

Хакерский способ, который я нашел, чтобы сделать это:

В моем классе действий, который перенаправляет в корзину, я делаю:

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

Затем я добавил на свою корзину следующее:

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

Тогда в моем блоке у меня есть:

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

И мой Refresh.phpкласс действий выглядит так:

<?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])
        );
    }
}
Рафаэль в цифровом пианизме
источник
Рафаэль, мой section.xml даже не пытается обновить корзину, когда я отправляю почтовый запрос на ссылку в файле ... Есть идеи?
LM_Fielding
@LM_Fielding да У меня были те же люди, прочитайте мой ответ
Рафаэль в Digital Pianism
Чтобы заставить его работать, мы должны написать это? Поведение по умолчанию нарушено или я неправильно понимаю?
LM_Fielding
@LM_Fielding хорошо, я не знаю, поэтому я задал этот вопрос, и я не получил хорошего ответа об этом. Как я уже сказал, это «хакерский» способ, которым я нашел это сделать.
Рафаэль на цифровом пианизме
Он определенно использовал относительный URL для меня - это не вызывает обновление раздела.
LM_Fielding
0

Я столкнулся с той же проблемой, что и автор вопроса. После нескольких часов изучения документации и основного кода я внезапно нашел решение. В моем случае я получил ... / etc / frontend / section.xml файл с

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

И это не хотело работать. После прочтения этой темы и этой проблемы https://github.com/magento/magento2/issues/3287 я был настолько растерян, что начал экспериментировать. Для меня помогает добавление слешей:

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

Надеюсь, это поможет кому-то потратить меньше времени на поиск решения.

Алекс Козырь
источник