이름없이 레이아웃에서 블록 제거


12

타사 확장으로 선언 된 magento 2의 레이아웃에서 블록을 제거하려고하지만 블록에 이름이 없습니다.
내가 할 수 있습니까?

블록은 다음과 같이 선언됩니다

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

사용할 수 없습니다

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

보시다시피 이름이 없기 때문입니다.


마리우스, 나는 아이디어가있다. 만약 우리가 이벤트를 사용하고 매치 템플릿 이름으로 블록을 제거한다면 [Vendor_Module]::template.phtml
Amit Bera

나는 같은 생각을 가지고 있지만 (답변에 대한 의견 참조) 필사적으로 사용해야합니다. 간단한 해결책을 원했습니다. 코드가 있으면 답변으로 게시하십시오.
Marius

하 우리는 간단한 해결책이 없다고 생각합니다. 이벤트를 사용하여 대답을 해보도록하겠습니다
Amit Bera

답변:


5

수업 시간에이 문제를 발견했습니다 Magento\Framework\View\Layout\ScheduledStructure\Helper

기능이 있습니다 _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++;
}

scheduleStructure함수 에서 호출 합니다.

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

이 경우 차단 이름은 다음과 같습니다.

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

컨테이너에 이름이없는 총 블록을 정의해야하며 주문 블록 이름은 컨테이너에서 제거해야한다고 생각합니다.


나는 이것이 효과가 없을 것이라고 생각한다. 다른 페이지에는 body.before.end다른 순서로 컨테이너에 여러 블록이 추가 될 수 있으므로 생성 된 이름을 예측할 수있는 방법이 없습니다 .
Marius

이 경우 이름이없는 블록 / 컨테이너에만 적용됩니다. 이름이없는 모든 블록 / 컨테이너를 정의하기 어려운 경우 제거해야합니다.
Thao Pham

그래 ... 내 문제는 정확히
마리우스

우리는 다시 작성 $name = $this->_generateAnonymousName($parentNode->getElementName() . '_schedule_block');해야합니다. 매개 변수에 클래스 및 템플릿을 전달해야합니까?
Thao Pham

2
그런 식으로 다시 작성하는 오버 헤드처럼 보입니다. 간단한 해결책 (있는 경우) 또는 '매우 쉽게 불가능하지 않은'과 같은 대답을 찾고 있습니다. 레이아웃이 블록 이벤트를 생성하거나 이벤트를 제거하는 것을 관찰 할 수 있다고 생각하지만 오버 헤드가 너무 많습니다. 나는 그것을 백업 솔루션으로 유지하고 있습니다.
Marius

3

나는 정말로 나쁜 생각을한다.

여기서 아이디어는 블록의 출력을 멈추지 않습니다.

이벤트 사용 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>

이 옵저버를 사용하면 블록의 출력을 비활성화합니다

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

    }
  }
}

이것은 실제로 그렇게 나쁜 생각이 아닙니다. 실제로 모든 블록을 관찰하는 과잉이 있지만 다른 옵션보다 기꺼이 사용하려고합니다. 노력하고 알려 드리겠습니다.
Marius

쿨. 남자 .. 어떻게되는지보기
Amit Bera

1
작동하지만 모든 블록에 대해 코드를 실행하지 말고 조금 최적화하려고했습니다. 그래서 나는 내 대답으로 끝났다 . 아이디어 주셔서 감사합니다.
Marius

나는 정말 좋은 사람이 대답을 참조하십시오 :)
Amit Bera

3

Amit의 답변 에서 아이디어를 얻었 으며 매우 방해가되지 않는 작동하는 솔루션으로 끝나고 코드가 한 번만 실행되므로 과잉이 아닙니다.

layout_generate_blocks_after레이아웃이로드되고 블록이 생성 된 후에 실행되는 이벤트에 대해 관찰자를 만들었습니다 .

제거하려는 블록이 여전히 인스턴스화되기 때문에 단점이있을 수 있지만 내 경우에는 페이지에서 블록을 제거해야했습니다.

그래서 파일이 있습니다 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>

내 관찰자 수업 :

<?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);
            }
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.