Magento 2:客户区段/sections.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模块以某种方式处理。

  • 这些部分到底是什么?您如何定义部分?
  • 如何触发节更新?
  • (可选)当我到达购物车页面时,如何修复测试代码以更新小型购物车?

这是在控制器中触发的,还是通过执行方法或其他方式引用的动作?
LM_Fielding '16

1
@LM_Fielding,请参阅我刚刚发布的答案:magento.stackexchange.com/a/142350/2380
Raphael在Digital Pianism上

Answers:


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>

因此,这里两个新节登记cartdirectory-dataMagento\Checkout\CustomerData\Cart并根据方法Magento\Checkout\CustomerData\DirectoryData实现Magento\Customer\CustomerData\SectionSourceInterface并提供实际数据getSectionData

如何触发节更新?

Magento的假定当客户发送一些状态修改请求(用户的私人数据被改变POSTPUTDELETE)。为了最大程度地减少服务器上的负载,开发人员应在中指定哪个操作(或请求)更新哪个客户数据部分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.jsmagento2ce/app/code/Magento/Customer/view/frontend/web/js/customer-data.js

在两个事件处理程序的最后一个结束时,为ajaxComplete和注册submit。这意味着当任何形式(使用POST或PUT方法)发布到服务器时,或者JavaScript发送AJAXPOSTPUT请求时,将调用处理程序。两种处理程序都有相似的逻辑:在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请求进行更新

此外,只有两个注意事项:

  • 这里描述的所有内容都是内部实现,可以更改,因此您可以安全地仅使用sections.xml,并期望在触发指定的POST或PUT或DELETE操作时更新部分。
  • 如果您确定确实需要更新某些部分,则可以始终执行以下操作: require('Magento_Customer/js/customer-data').reload(['cart'], false)

太感谢了。您能以什么方式告诉我,为什么我到达购物车页面时问题中的代码没有刷新迷你购物车?
拉斐尔(Raphael)在

1
@RaphaelatDigitalPianism,我已经用答案更新了我的评论
Volodymyr Kublytskyi,2016年

我正在购物车页面中进行自定义ajax调用,不需要此客户负载部分调用。如何避免这种情况?magento.stackexchange.com/questions/156425/…–
seei

5

您在标记中定义的操作应通过POST请求引发。例如:

另外,如果您想刷新所有部分中的客户数据,只需使用(请参阅vendor / magento / module-customer / etc / frontend / sections.xml)

您还可以查看文件末尾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(sections); 
        } 
    } 
});

您也可以查看文件供应商/magento/module-customer/view/frontend/web/js/section-config.js文件的末尾。找到代码$(document).on('submit',function(event){var区段; if(event.target.method.match(/ post | put / i)){区段= sectionConfig.getAffectedSections(event.target.action); if(sections){customerData.invalidate(sections;}}}) ;
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])
        );
    }
}

拉斐尔(Raphael),当我向文件中的url发送发布请求时,我的sections.xml甚至都没有尝试更新购物车...有什么想法吗?
LM_Fielding '16

@LM_Fielding是的,我有同样的人,请阅读我的回答
Raphael在Digital Pianism上2016年

因此,要使其正常工作,我们必须编写此代码?默认行为是否被破坏或我误解了?
LM_Fielding '16

@LM_Fielding好,我不知道这就是为什么我问这个问题,而我对此没有任何好的答案。正如我所说的,这是我发现的“ hacky”方式。
拉斐尔(Raphael)在Digital Pianism上,2013年

绝对是为我使用了相对网址-它不会触发该部分的更新。
LM_Fielding '16

0

我曾与问题作者面临同样的问题。经过数小时的研究和开发文档和核心代码,我突然找到了解决方案。就我而言,我有... / 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="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>

希望它可以帮助某人减少寻找解决方案的时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.