从布局中删除没有名称的图块


12

我想从magento 2的布局中删除一个在第三方扩展中声明的块,但是该块没有名称。
我可以那样做吗?

这样声明该块

<referenceContainer name="before.body.end">
    <block class="Magento\Backend\Block\Template" template="[Vendor_Module]::template.phtml"/>
</referenceContainer>

我不能使用

<referenceBlock name="..." remove="true" /> 

因为,如您所见,上面没有名称。


马里乌斯,我有主意。如果我们使用事件并通过匹配模板名称删除块 [Vendor_Module]::template.phtml
阿米特·贝拉

我有相同的想法(请参阅答案),但我只会将其用作绝望的措施。我希望有一个简单的解决方案。如果您有一些代码,请将其发布为答案。
马吕斯

哈哈,我们没有简单的解决方案。让我尝试使用事件给您一个答案
阿米特·贝拉

Answers:


5

我在课堂上发现了这个问题 Magento\Framework\View\Layout\ScheduledStructure\Helper

有功能_generateAnonymousName

protected function _generateAnonymousName($class)
{
    $position = strpos($class, '\\Block\\');
    $key = $position !== false ? substr($class, $position + 7) : $class;
    $key = strtolower(trim($key, '_'));
    return $key . $this->counter++;
}

scheduleStructure函数调用:

    public function scheduleStructure(
    Layout\ScheduledStructure $scheduledStructure,
    Layout\Element $currentNode,
    Layout\Element $parentNode
) {
    // if it hasn't a name it must be generated
    if (!(string)$currentNode->getAttribute('name')) {
        $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block'); // CALL HERE
        $currentNode->setAttribute('name', $name);
    }
    $path = $name = (string)$currentNode->getAttribute('name');

    // Prepare scheduled element with default parameters [type, alias, parentName, siblingName, isAfter]
    $row = [
        self::SCHEDULED_STRUCTURE_INDEX_TYPE           => $currentNode->getName(),
        self::SCHEDULED_STRUCTURE_INDEX_ALIAS          => '',
        self::SCHEDULED_STRUCTURE_INDEX_PARENT_NAME    => '',
        self::SCHEDULED_STRUCTURE_INDEX_SIBLING_NAME   => null,
        self::SCHEDULED_STRUCTURE_INDEX_IS_AFTER       => true,
    ];

    $parentName = $parentNode->getElementName();
    //if this element has a parent element, there must be reset [alias, parentName, siblingName, isAfter]
    if ($parentName) {
        $row[self::SCHEDULED_STRUCTURE_INDEX_ALIAS] = (string)$currentNode->getAttribute('as');
        $row[self::SCHEDULED_STRUCTURE_INDEX_PARENT_NAME] = $parentName;

        list($row[self::SCHEDULED_STRUCTURE_INDEX_SIBLING_NAME],
            $row[self::SCHEDULED_STRUCTURE_INDEX_IS_AFTER]) = $this->_beforeAfterToSibling($currentNode);

        // materialized path for referencing nodes in the plain array of _scheduledStructure
        if ($scheduledStructure->hasPath($parentName)) {
            $path = $scheduledStructure->getPath($parentName) . '/' . $path;
        }
    }

    $this->_overrideElementWorkaround($scheduledStructure, $name, $path);
    $scheduledStructure->setPathElement($name, $path);
    $scheduledStructure->setStructureElement($name, $row);
    return $name;
}

在这种情况下,块名称可以是:

  • before.body.end_schedule_block1
  • before.body.end_schedule_block2
  • ...

我认为您应该在容器上没有名称的情况下定义总计块,并且需要在容器上删除订单块名称。


我认为这行不通。无法预测生成的名称,因为在不同的页面上可能body.before.end以不同的顺序在容器中添加了多个块。
马吕斯

这种情况仅适用于没有名称的块/容器。如果所有这些都没有名称,那么很难定义一些需要删除的块/容器。
Thao Pham

是的...我的问题恰恰是
马吕斯

我们应该重写$name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');,是否应该将类和模板传递给参数?
Thao Pham

2
重写这样的内容似乎是一笔开销。我正在寻找一个简单的解决方案(如果有的话)或“不可能很容易”这样的答案。我想我可以观察到布局生成块事件或将其删除的事件,但似乎又有太多开销。我将其作为备份解决方案。
马吕斯

3

我真的给你个坏主意。

这里的想法不是停止块的输出

使用事件 view_block_abstract_to_html_after

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="view_block_abstract_to_html_after">
        <observer name="myObserverName" instance="Stack\Work\Observer\MyObserver" />
    </event>
</config>

并使用此观察器禁用块的输出

<?php
namespace Stack\Work\Observer;
use Magento\Framework\Event\ObserverInterface;

class MyObserver implements ObserverInterface
{
  public function __construct()
  {
    //Observer initialization code...
    //You can use dependency injection to get any class this observer may need.
  }

  public function execute(\Magento\Framework\Event\Observer $observer)
  {
    $block = $observer->getData('block');

    if('[Vendor_Module]::template.phtml' == $block->getTemplate()){
        $transport = $observer->getData('transport');
        $transport->setHtml('');

    }
  }
}

这实际上不是一个坏主意。确实,观察所有障碍物是一种矫kill过正,但我​​愿意在其他选项上使用它。我会尽力让您知道。
马吕斯

酷。男人....看看会发生什么
阿米特·贝拉

1
它可以工作,但是我尝试对其进行一些优化,而不是为每个块执行代码。所以我最后给出了答案。谢谢你的主意。
马吕斯

我看到了答案,那个好人:)
阿米特·贝拉

3

我从Amit的答案中得到了一个主意,最后得到了一个可行的解决方案,该解决方案看上去并不那么令人讨厌,并且也不算过分,因为我的代码仅执行一次。

我已经在layout_generate_blocks_after加载布局和生成块之后执行的事件上创建了一个观察者。

这可能会有一个缺点,因为我尝试删除的块仍然被实例化,但就我而言,我只需要从页面中删除它。

所以我有文件 etc/adminhtml/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="layout_generate_blocks_after">
        <observer name="remove-the-block" instance="[MyVendor]\[MyModule]\Observer\RemoveBlock" />
    </event>
</config>

和我的观察员班:

<?php
namespace [MyVendor]\[MyModule]\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class RemoveBlock implements ObserverInterface
{
    const TEMPLATE_TO_REMOVE = '[OtherVendor]_[OtherModule]::template.phtml';
    public function execute(Observer $observer)
    {
        /** @var \Magento\Framework\View\Layout $layout */
        $layout = $observer->getLayout();
        $blocks = $layout->getAllBlocks();
        foreach ($blocks as $key => $block) {
            /** @var \Magento\Framework\View\Element\Template $block */
            if ($block->getTemplate() == self::TEMPLATE_TO_REMOVE) {
                $layout->unsetElement($key);
            }
        }
    }
}
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.