Rimuovi un blocco dal layout senza un nome


12

Voglio rimuovere un blocco dal layout in magento 2 dichiarato in un'estensione di terze parti, ma il blocco non ha un nome.
Posso farlo?

Il blocco è dichiarato in questo modo

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

Non posso usare

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

perché, come puoi vedere, non vi è alcun nome.


marius, ho idea. se utilizziamo un evento e rimuoviamo il blocco in base al nome del modello di partita [Vendor_Module]::template.phtml
Amit Bera

Ho la stessa idea (vedi commenti sulla risposta) ma la userò solo come misura disperata. Speravo in una soluzione semplice. Se hai del codice, pubblicalo come risposta.
Marius

ah ah ah non abbiamo una soluzione semplice. fammi provare a darti una risposta usando l'evento
Amit Bera

Risposte:


5

Ho riscontrato questo problema in classe Magento\Framework\View\Layout\ScheduledStructure\Helper

C'è una funzione _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++;
}

Si chiama dalla scheduleStructurefunzione:

    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 questo caso, il nome del blocco può essere:

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

Penso che dovresti definire il blocco dei totali senza il nome sul contenitore e il nome del blocco ordine deve essere rimosso sul contenitore.


Non penso che funzionerà. Non è possibile prevedere il nome generato poiché su pagine diverse possono essere aggiunti più blocchi nel body.before.endcontenitore in ordine diverso.
Marius

Questo caso si applica solo al blocco / contenitore senza un nome. Se tutti loro senza il nome, è così difficile definire alcuni blocchi / container devono essere rimossi.
Thao Pham,

sì ... il mio problema esattamente
Marius

Dovremmo riscrivere $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');, dovrebbe essere passare la classe e il modello al parametro?
Thao Pham,

2
sembra un sovraccarico per riscrivere qualcosa del genere. Sto cercando una soluzione semplice (se presente) o una risposta come "non possibile molto facilmente". Penso di poter osservare il layout generare blocchi di eventi o qualcosa per rimuoverlo lì, ma sembra di nuovo troppo sovraccarico. Lo sto mantenendo come soluzione di backup.
Marius

3

Ti sto davvero dando una cattiva idea.

Qui l'idea non è di interrompere l'output del blocco

Utilizzo dell'evento 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>

E usando questo osservatore disabilita l'output del tuo blocco

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

    }
  }
}

questa non è in realtà una cattiva idea. In effetti c'è un eccessivo rispetto di tutti i blocchi, ma sono disposto a usarlo su altre opzioni. Proverò a farti sapere.
Marius

coool. amico .... guarda cosa succede
Amit Bera

1
Funziona, ma ho cercato di ottimizzarlo un po ', non di eseguire il codice per ogni blocco. Quindi ho finito con la mia risposta . Grazie per l'idea
Marius

Vedo la risposta, quell'uomo davvero bravo :)
Amit Bera

3

Ho avuto un'idea dalla risposta di Amit e ho finito con una soluzione funzionante che non sembra molto invadente e non è eccessiva poiché il mio codice viene eseguito solo una volta.

Ho creato un osservatore sull'evento layout_generate_blocks_afterche viene eseguito dopo il caricamento dei layout e la generazione dei blocchi.

Questo può avere uno svantaggio perché il blocco che sto cercando di rimuovere viene ancora istanziato, ma nel mio caso avevo solo bisogno di rimuoverlo dalla pagina.

Quindi ho il 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>

e la mia classe di osservatori:

<?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);
            }
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.