Supprimer un bloc de la mise en page sans nom

12

Je souhaite supprimer un bloc de la mise en page dans magento 2 qui est déclaré dans une extension tierce, mais le bloc n'a pas de nom.
Puis-je faire cela?

Le bloc est déclaré comme ceci

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

Je ne peux pas utiliser

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

car, comme vous pouvez le voir, il n'y a pas de nom dessus.

Marius
la source
marius, j'ai idée.si nous utilisons l'événement et supprimons le bloc par nom de modèle de correspondance [Vendor_Module]::template.phtml
Amit Bera
J'ai la même idée (voir les commentaires sur la réponse) mais je ne l'utiliserai que comme mesure désespérée. J'espérais une solution simple. Si vous avez du code, postez-le comme réponse.
Marius
ha ha que nous n'avons pas de solution simple. laissez-moi essayer de vous donner une réponse en utilisant l'événement
Amit Bera

Réponses:

5

J'ai trouvé ce problème en classe Magento\Framework\View\Layout\ScheduledStructure\Helper

Il y a une fonction _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++;
}

C'est l'appel de la scheduleStructurefonction:

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

Dans ce cas, le nom du bloc peut être:

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

Je pense que vous devez définir le bloc des totaux sans le nom sur le conteneur et le nom du bloc de commande doit être supprimé sur le conteneur.

Thao Pham
la source
Je ne pense pas que cela fonctionnera. Il n'y a aucun moyen de prédire le nom généré car sur différentes pages, il peut y avoir plusieurs blocs ajoutés dans le body.before.endconteneur dans un ordre différent.
Marius
Ce cas s'applique uniquement au bloc / conteneur sans nom. Si tous sans nom, il est si difficile de définir un bloc / conteneur à supprimer.
Thao Pham
yep ... mon problème exactement
Marius
Nous devrions réécrire $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');, Devrait-on passer la classe et le modèle au paramètre?
Thao Pham
2
semble être une surcharge pour réécrire quelque chose comme ça. Je cherche une solution simple (le cas échéant) ou une réponse comme «pas possible très facilement». Je pense que je peux observer la mise en page générer un événement de blocs ou quelque chose pour le supprimer ici, mais encore une fois, cela semble trop lourd. Je garde cela comme solution de sauvegarde.
Marius
3

Je vous donne vraiment une mauvaise idée.

Ici l'idée n'est pas d'arrêter la sortie de votre bloc

Utilisation de l'événement 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>

Et en utilisant cet observateur, désactivez la sortie de votre bloc

<?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
la source
ce n'est pas vraiment une si mauvaise idée. En effet, il y a une surpuissance à observer tous les blocs, mais je suis prêt à l'utiliser sur d'autres options. Je vais essayer de vous le faire savoir.
Marius
coool. homme .... voir ce qui se passe
Amit Bera
1
Cela fonctionne, mais j'ai essayé de l'optimiser un peu, de ne pas exécuter le code pour chaque bloc. Je me suis donc retrouvé avec ma réponse . Merci pour l'idée.
Marius
Je vois la réponse, cet homme vraiment bon :)
Amit Bera
3

J'ai eu une idée de la réponse d' Amit et je me suis retrouvé avec une solution de travail qui ne semble pas très intrusive et ce n'est pas une surpuissance puisque mon code n'est exécuté qu'une seule fois.

J'ai créé un observateur sur l'événement layout_generate_blocks_afterqui est exécuté après le chargement des présentations et la génération des blocs.

Cela peut avoir un inconvénient car le bloc que j'essaie de supprimer est toujours instancié, mais dans mon cas, je devais juste le supprimer de la page.

J'ai donc le dossier 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>

et ma classe d'observateur:

<?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
la source