Entfernen Sie einen Block ohne Namen aus dem Layout

11

Ich möchte einen Block aus dem Layout in Magento 2 entfernen, der in einer Drittanbietererweiterung deklariert ist, aber der Block hat keinen Namen.
Kann ich das machen?

Der Block wird so deklariert

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

Ich kann nicht benutzen

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

denn wie Sie sehen, steht kein Name darauf.

Marius
quelle
Marius, ich habe eine Idee. Wenn wir ein Ereignis verwenden und den Block nach dem Namen der Übereinstimmungsvorlage entfernen [Vendor_Module]::template.phtml
Amit Bera
Ich habe die gleiche Idee (siehe Kommentare zur Antwort), aber ich werde sie nur als verzweifelte Maßnahme verwenden. Ich hatte auf eine einfache Lösung gehofft. Wenn Sie einen Code haben, geben Sie ihn als Antwort ein.
Marius
ha ha, dass wir keine einfache Lösung haben. Lassen Sie mich versuchen, Ihnen eine Antwort mit event
Amit Bera zu geben

Antworten:

5

Ich habe dieses Problem im Unterricht gefunden Magento\Framework\View\Layout\ScheduledStructure\Helper

Es gibt Funktion _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++;
}

Es ist ein Aufruf von der scheduleStructureFunktion:

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

In diesem Fall kann der Blockname sein:

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

Ich denke, Sie sollten den Summenblock ohne den Namen auf dem Container definieren und den Namen des Bestellblocks auf dem Container entfernen.

Thao Pham
quelle
Ich denke nicht, dass das funktionieren wird. Es gibt keine Möglichkeit, den generierten Namen vorherzusagen, da auf verschiedenen Seiten mehrere Blöcke body.before.endin unterschiedlicher Reihenfolge in den Container eingefügt werden können.
Marius
Dieser Fall gilt nur für Block / Container ohne Namen. Wenn alle ohne Namen, so schwer zu definieren, müssen einige Blöcke / Container entfernt werden.
Thao Pham
yep ... mein Problem genau
Marius
Wir sollten umschreiben $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');, sollten Klasse & Vorlage an Parameter übergeben werden?
Thao Pham
2
scheint ein Overhead zu sein, um so etwas neu zu schreiben. Ich suche nach einer einfachen Lösung (falls vorhanden) oder einer Antwort wie "nicht sehr einfach möglich". Ich denke, ich kann beobachten, wie das Layout Blockereignisse generiert oder etwas, um es dort zu entfernen, aber es scheint wieder zu viel Aufwand zu sein. Ich behalte das als Backup-Lösung.
Marius
2

Ich gebe dir wirklich eine schlechte Idee.

Hier ist die Idee nicht, die Ausgabe Ihres Blocks zu stoppen

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

Und mit diesem Beobachter deaktivieren Sie die Ausgabe Ihres Blocks

<?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('');

    }
  }
}
Amit Bera
quelle
Das ist eigentlich keine so schlechte Idee. In der Tat gibt es einen Overkill, der alle Blöcke beobachtet, aber ich bin bereit, ihn gegenüber anderen Optionen zu verwenden. Ich werde versuchen, es dich wissen zu lassen.
Marius
coool. Mann ... sehen, was passiert
Amit Bera
1
Es funktioniert, aber ich habe versucht, es ein wenig zu optimieren, nicht den Code für jeden Block auszuführen. Also habe ich meine Antwort erhalten . Danke für die Idee.
Marius
Ich sehe Antwort, dieser wirklich gute Mann :)
Amit Bera
2

Ich hatte eine Idee aus Amits Antwort und fand eine funktionierende Lösung, die nicht sehr aufdringlich aussieht und kein Overkill ist, da mein Code nur einmal ausgeführt wird.

Ich habe einen Beobachter für das Ereignis erstellt layout_generate_blocks_after, das ausgeführt wird, nachdem die Layouts geladen und die Blöcke generiert wurden.

Dies kann einen Nachteil haben, da der Block, den ich entfernen möchte, immer noch instanziiert wird, aber in meinem Fall musste ich ihn nur von der Seite entfernen.

Also habe ich die Datei 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>

und meine Beobachterklasse:

<?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);
            }
        }
    }
}
Marius
quelle