Hapus blok dari tata letak tanpa nama

12

Saya ingin menghapus blok dari tata letak di magento 2 yang dideklarasikan dalam ekstensi pihak ketiga, tetapi blok itu tidak memiliki nama.
Bisakah saya melakukan itu?

Blok dideklarasikan seperti ini

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

Saya tidak bisa menggunakan

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

karena, seperti yang Anda lihat tidak ada nama di dalamnya.

Marius
sumber
marius, saya punya ide. jika kita menggunakan acara dan menghapus blok dengan nama template yang cocok [Vendor_Module]::template.phtml
Amit Bera
Saya memiliki ide yang sama (lihat komentar pada jawabannya) tetapi saya akan menggunakannya hanya sebagai ukuran putus asa. Saya berharap untuk solusi sederhana. Jika Anda memiliki beberapa kode, poskan sebagai jawaban.
Marius
ha ha kita donot punya solusi sederhana.boleh saya coba beri kamu jawaban menggunakan acara
Amit Bera

Jawaban:

5

Saya menemukan masalah ini di kelas Magento\Framework\View\Layout\ScheduledStructure\Helper

Ada fungsi _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++;
}

Ini panggilan dari scheduleStructurefungsi:

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

Dengan kasus ini, nama Blok dapat:

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

Saya pikir Anda harus mendefinisikan total blok tanpa nama pada wadah dan urutan nama blok harus dihapus pada wadah.

Thao Pham
sumber
Saya tidak berpikir ini akan berhasil. Tidak ada cara untuk memprediksi nama yang dihasilkan karena pada halaman yang berbeda ada beberapa blok yang ditambahkan dalam body.before.endwadah dengan urutan yang berbeda.
Marius
Kasing ini hanya berlaku untuk blok / wadah tanpa nama. Jika semuanya tanpa nama, maka sulit untuk mendefinisikan beberapa blok / wadah yang perlu dihilangkan.
Thao Pham
ya ... masalah saya tepatnya
Marius
Kita harus menulis ulang $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');, Harus lulus kelas & template ke parameter?
Thao Pham
2
Sepertinya overhead untuk menulis ulang sesuatu seperti itu. Saya mencari solusi sederhana (jika ada) atau jawaban seperti 'tidak mungkin dengan sangat mudah'. Saya pikir saya bisa mengamati tata letak menghasilkan blok acara atau sesuatu untuk menghapusnya di sana, tetapi sekali lagi tampaknya terlalu banyak overhead. Saya menyimpannya sebagai solusi cadangan.
Marius
3

Saya benar-benar memberi Anda ide buruk.

Di sini idenya tidak menghentikan output dari blok Anda

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

Dan menggunakan pengamat ini menonaktifkan output dari blok Anda

<?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
sumber
ini sebenarnya bukan ide yang buruk. Memang ada banyak kerja keras mengamati semua blok, tapi saya bersedia menggunakannya atas opsi lain. Saya akan mencoba dan memberi tahu Anda.
Marius
pendingin. *** .... lihat apa yang terjadi
Amit Bera
1
Berhasil, tetapi saya mencoba sedikit mengoptimalkannya, bukan untuk mengeksekusi kode untuk setiap blok. Jadi saya berakhir dengan jawaban saya . Terima kasih untuk idenya.
Marius
Saya melihat jawaban, pria yang sangat baik itu :)
Amit Bera
3

Saya mendapat ide dari jawaban Amit dan berakhir dengan solusi yang bekerja yang tidak terlihat sangat mengganggu dan itu tidak berlebihan karena kode saya dieksekusi hanya sekali.

Saya telah membuat pengamat pada acara layout_generate_blocks_afteryang dieksekusi setelah tata letak dimuat dan blok dihasilkan.

Ini dapat memiliki kekurangan karena blok yang saya coba hapus masih akan dipakai, tetapi dalam kasus saya, saya hanya perlu menghapusnya dari halaman.

Jadi saya punya file 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>

dan kelas pengamat saya:

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