Magento 2: як працюють розділи / секції.xml клієнтів?


49

Нещодавно я натрапив на нову концепцію 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

Відповіді:


82

Які саме ці розділи?

Розділ - це частина даних про клієнтів, згрупованих разом. Кожен розділ представлений ключем, який використовується для доступу та управління самими даними та даними. 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/…
seeni

5

Дія, яку ви вказали в тезі, повинна викликатися через POST-запит. наприклад:

Крім того, якщо ви хочете оновити дані клієнтів у всіх розділах, просто використовуйте (Подивіться на постачальника / magento / module-customer / тощо / frontend / section.xml)

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

$ (документ) .on ('подати', функція (подія) { 
    вар розділи; 
    якщо (event.target.method.match (/ post | put / i)) { 
        секції = sectionConfig.getAffectedSections (event.target.action);
        якщо (розділи) { 
            customerData.invalidate (розділи); 
        } 
    } 
});

Ви також можете подивитися в кінці файлу vendor / magento / module-customer / view / frontend / web / js / section-config.js Знайти код $ (document) .on ('submit', function (event) {var розділи; якщо (event.target.method.match (/ post | put / i)) {section = sectionConfig.getAffectedSections (event.target.action); якщо (розділи) {customerData.invalidate (розділи);}}}) ;
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])
        );
    }
}

Рафаель, мої секції.xml навіть не намагаються оновити кошик, коли я надсилаю запит на пошту до URL у файлі ... Будь-які ідеї?
LM_Fielding

@LM_Fielding Так, у мене були ті самі люди, прочитайте мою відповідь
Рафаель у Digital Pianism

Отже, щоб змусити його працювати, ми повинні це написати? Чи порушена поведінка за замовчуванням чи я нерозумію?
LM_Fielding

@LM_Fielding добре, я не знаю, тому я задав це питання, і я не отримав жодної хорошої відповіді на це. Як я вже говорив, це "хакітний" спосіб, який я знайшов.
Рафаель у Digital Pianism

Напевно для мене використовується відносна 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/isissue/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>

Сподіваюся, це допоможе комусь витратити менше часу на пошук рішення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.