Remover um bloco do layout sem nome

12

Quero remover um bloco do layout no magento 2 declarado em uma extensão de terceiros, mas o bloco não tem um nome.
Posso fazer isso?

O bloco é declarado assim

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

Não posso usar

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

porque, como você pode ver, não há nome nele.

Marius
fonte
Marius, eu tenho idea.if nós usando evento e bloco de remoção por nome do modelo jogo [Vendor_Module]::template.phtml
Amit Bera
Eu tenho a mesma idéia (ver comentários na resposta), mas a usarei apenas como uma medida desesperada. Eu esperava uma solução simples. Se você tiver algum código, publique-o como resposta.
Marius
ha ha que doador tem solution.let simples me tentar dar u uma resposta usando o evento
Amit Bera

Respostas:

5

Encontrei esse problema na aula Magento\Framework\View\Layout\ScheduledStructure\Helper

Há função _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++;
}

É chamada de scheduleStructurefunção:

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

Nesse caso, o nome do bloco pode ser:

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

Eu acho que você deve definir o bloco de totais sem o nome no contêiner e o nome do bloco do pedido precisa ser removido no contêiner.

Thao Pham
fonte
Eu não acho que isso vai funcionar. Não há como prever o nome gerado, pois em páginas diferentes podem haver vários blocos adicionados no body.before.endcontêiner em ordem diferente.
Marius
Este caso se aplica apenas ao bloco / contêiner sem nome. Se todos eles sem o nome, é tão difícil definir algum bloco / contêiner precisa ser removido.
Thao Pham
sim ... meu problema exatamente
Marius
Devemos reescrever $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');. Deve passar a classe e o modelo para o parâmetro?
Thao Pham
2
parece uma sobrecarga para reescrever algo assim. Estou procurando uma solução simples (se houver) ou uma resposta como 'não é possível com muita facilidade'. Eu acho que posso observar o layout gerar evento de blocos ou algo para removê-lo lá, mas novamente parece sobrecarga demais. Estou mantendo isso como uma solução de backup.
Marius
3

Estou realmente te dando uma má idéia.

Aqui a ideia não é parar a saída do seu bloco

Usando 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 esse observador, desative a saída do seu bloco

<?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
fonte
isso não é realmente uma má idéia. De fato, há um exagero observando todos os blocos, mas estou disposto a usá-lo em outras opções. Vou tentar e informá-lo.
Marius
coool. cara .... veja o que acontece #
Amit Bera
1
Funciona, mas tentei otimizá-lo um pouco, para não executar o código para cada bloco. Então acabei com a minha resposta . Obrigado pela ideia.
Marius
Vejo resposta, que homem realmente bom :)
Amit Bera
3

Tive uma idéia da resposta de Amit e acabei com uma solução funcional que não parece muito intrusiva e não é um exagero, pois meu código é executado apenas uma vez.

Eu criei um observador no evento layout_generate_blocks_afterque é executado depois que os layouts são carregados e os blocos são gerados.

Isso pode ter uma desvantagem, porque o bloco que estou tentando remover ainda é instanciado, mas no meu caso, eu apenas precisei removê-lo da página.

Então eu tenho o arquivo 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 minha classe de observador:

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