Magento 2: Bir yapılandırma ayarına bağlı olarak bloğu kaldır


13

Belirli bir sayfadan (ön uç veya arka uç olsun) bir blok kaldırmaya çalışıyorum ama sadece belirli bir yapılandırma bayrağı olarak ayarlanmışsa true.
Bir örnek verelim.
Adlı bloğu dashboardyönetici kontrol panelinden kaldırmak istiyorum .

Blok, modüldeki adminhtml_dashboard_index.xmldosyada tanımlanır Magento_Backend:

<referenceContainer name="content">
    <block class="Magento\Backend\Block\Dashboard" name="dashboard"/>
</referenceContainer>

Adem'in cevabı sayesinde bunuadminhtml_dashboard_index.xml

<body>
    <referenceBlock name="dashboard" remove="true"  />
</body>

Ama ben bir çentik almak ve sadece yol ile yapılandırma ayarı dashboard/settings/removedeğeri varsa bu bloğu kaldırmak istiyorum 1.
Bir düzen xml yaklaşımı harika olurdu, ama ben de gözlemci bir yaklaşım alacağım.


Marius, aynı şey events.xml için kullanılabilir biliyor musunuz? Yani yapılandırma etkinleştirilirse gözlemcimi yürütmek istiyorum
Keyur Shah

Yanıtlar:


17

Bunu mizanpajla da yapmanın bir yolunu bulamadım ama işte gözlemcilerle (Şablon bloğunu genişletmeleri şartıyla) yapabileceğiniz bir yol örneği ...

Events.xml dosyasını etc / events.xml dosyasında oluşturun

<?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_before">
        <observer name="remove_block" instance="[Vendor]\[ModuleName]\Model\Observer\RemoveBlock" />
    </event>
</config>

Gözlemciyi oluşturun

<?php

namespace [Vendor]\[ModuleName]\Model\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class RemoveBlock implements ObserverInterface
{
    protected $_scopeConfig;

    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    ) {
        $this->_scopeConfig = $scopeConfig;
    }

    public function execute(Observer $observer)
    {
        /** @var \Magento\Framework\View\Element\Template $block */
        $block = $observer->getBlock();
        if ($block->getType() == 'Magento\Backend\Block\Dashboard') {
            $remove = $this->_scopeConfig->getValue(
                'dashboard/settings/remove',
                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
            );

            if ($remove) {
                $block->setTemplate(false);
            }
        }
    }
}

Temel olarak _toHtml bir şablon olup olmadığını kontrol eder. Eğer yoksa geri döner ''.

DÜZENLE

Biraz daha kazma işleminden sonra bunu zincirde daha ileriye götürmenin bir yolunu buldum.

<?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_block" instance="[Vendor]\[ModuleName]\Model\Observer\RemoveBlock" />
    </event>
</config>

Ve gözlemci ...

<?php

namespace [Vendor]\[ModuleName]\Model\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class RemoveBlock implements ObserverInterface
{
    protected $_scopeConfig;

    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    ) {
        $this->_scopeConfig = $scopeConfig;
    }

    public function execute(Observer $observer)
    {
        /** @var \Magento\Framework\View\Layout $layout */
        $layout = $observer->getLayout();
        $block = $layout->getBlock('dashboard');
        if ($block) {
            $remove = $this->_scopeConfig->getValue(
                'dashboard/settings/remove',
                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
            );

            if ($remove) {
                $layout->unsetElement('dashboard');
            }
        }
    }
}

Bu işe yarayabilir, ancak yalnızca şablon kullanan bloklar için. Sağladığım örnek için geçerlidir, ancak yine de, AbstractBlock öğesini genişleten ve Template bloğunu genişletmeyen bloklar varsa, bu çalışmaz. İyi başlangıç ​​noktası için +1.
Marius

Haklısın. Biraz daha kazma işleminden sonra bunu daha önce yapabileceğinizi gördüm. Yanıt güncellendi. Orjinalimi referans için orada bıraktım.
Smartie

Teşekkürler bu yararlı bir cevap. Sorun şu ki, mantık "layout_generate_blocks_after" etkinliğini kullandığından her sayfa yüklemesinde tetikleneceği anlamına gelir. Yalnızca belirli sayfa yüklemelerinde nasıl çalıştırılacağını biliyor musunuz, örneğin bir kategori sayfası yükleme (etkinlik "catalog_controller_category_init_after" dır, ancak düzene erişilemez)?
Alex

2
Gerçekten mi?! Bir bloğu kaldırmak veya koşulsuz olarak kaldırmak için bir gözlemci yapmalıyız? bu sadece saçma.
slayerbleast

1
Gözlemciler bence verileri manipüle etmemeli ...
Alex

5

Normalde şu <action />etiketle yapılmalıdır :

<referenceContainer name="content">
    <action method="unsetChild" ifconfig="dashboard/settings/remove">
        <argument xsi:type="string">dashboard</argument>
    </action>
</referenceContainer>

DÜZENLE :

Çocuk yalnızca takma ad kabul eder. Blok adını kullanamazsınız.

Diğer çözüm: remove = "true" ile ifconfig'i kullanabilmek için Magento Framework'ü yeniden yazın

1- Kendi modülünüzü oluşturun.

Yeni bir dosya ekleme 2- Magento Framework geçersiz kılmak için: (örn: /Vendor/Module/Override/Magento/Framework/View/Layout/Reader/Block.php)

namespace Vendor\Module\Override\Magento\Framework\View\Layout\Reader;

use Magento\Framework\App;
use Magento\Framework\Data\Argument\InterpreterInterface;
use Magento\Framework\View\Layout;

/**
 * Block structure reader
 */
class Block extends \Magento\Framework\View\Layout\Reader\Block
{
    /**
     * @var \Magento\Framework\App\ScopeResolverInterface
     */
    protected $scopeResolver;

    /**
     * @var \Magento\Framework\App\Config\ScopeConfigInterface
     */
    protected $scopeConfig;

    /**
     * Constructor
     *
     * @param Layout\ScheduledStructure\Helper $helper
     * @param Layout\Argument\Parser $argumentParser
     * @param Layout\ReaderPool $readerPool
     * @param InterpreterInterface $argumentInterpreter
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Framework\App\ScopeResolverInterface $scopeResolver
     * @param string|null $scopeType
     */
    public function __construct(
        Layout\ScheduledStructure\Helper $helper,
        Layout\Argument\Parser $argumentParser,
        Layout\ReaderPool $readerPool,
        InterpreterInterface $argumentInterpreter,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Framework\App\ScopeResolverInterface $scopeResolver,
        $scopeType = null
    ) {
        parent::__construct($helper,
            $argumentParser,
            $readerPool,
            $argumentInterpreter,
            $scopeType
        );
        $this->scopeConfig = $scopeConfig;
        $this->scopeResolver = $scopeResolver;
    }

    protected function scheduleReference(
        Layout\ScheduledStructure $scheduledStructure,
        Layout\Element $currentElement
    ) {
        $elementName = $currentElement->getAttribute('name');
        $elementRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN);
        if ($elementRemove) {
            $configPath = (string)$currentElement->getAttribute('ifconfig');
            if (empty($configPath)
                || $this->scopeConfig->isSetFlag($configPath, $this->scopeType, $this->scopeResolver->getScope())
            ) {
                $scheduledStructure->setElementToRemoveList($elementName);
            }
        } else {
            $data = $scheduledStructure->getStructureElementData($elementName, []);
            $data['attributes'] = $this->mergeBlockAttributes($data, $currentElement);
            $this->updateScheduledData($currentElement, $data);
            $this->evaluateArguments($currentElement, $data);
            $scheduledStructure->setStructureElementData($elementName, $data);
        }
    }
}

3- Magento dosyasını geçersiz kılmak için di.xml dosyası ekleyin:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Framework\View\Layout\Reader\Block"
       type="Vendor\Module\Override\Magento\Framework\View\Layout\Reader\Block" />    
</config>

4- Artık düzende kaldır ile birlikte ifconfig komutunu kullanabilirsiniz:

<referenceBlock name="content" remove="true" ifconfig="path/to/myconfig" />

Bu örnek Block içindir, ancak /Magento/Framework/View/Layout/Reader/Container.php yönteminin containerReference () yöntemini geçersiz kılarsanız aynı işlemi kapsayıcı için de yapabilirsiniz.


Sanırım Framework'ü yeniden yazmak en iyi çözüm, magento'nun neden bu varsayılana sahip olmadığını bilmiyorum.
slayerbleast

3

Gönderen teknik kılavuzlar :

14.1. Bir olaya geçirilen tüm değerler (nesneler dahil), olay gözlemcisinde DEĞİŞTİRİLMEMELİDİR. Bunun yerine, eklentiler bir işlevin giriş veya çıkışını değiştirmek için KULLANILMALIDIR.

14.3. Olaylar, gözlemlenebilir nesnelerin durumunu DEĞİŞTİRMEMELİDİR.

İşte bunun için bir eklenti çözümü:

Eklentiyi bildirin:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\View\Element\AbstractBlock">
        <plugin name="remove_block" type="[Vendor]\[Module]\Plugin\RemoveBlock" />
    </type>
</config>

Eklentiyi tanımlayın:

<?php

namespace Vendor\Module\Plugin;


use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\View\Element\AbstractBlock;

class RemoveBlock
{
    const BLOCK_NAME = 'block_to_be_removed';

    const CONFIG_PATH = 'your/path';

    private $_scopeConfig;

    public function __construct(ScopeConfigInterface $scopeConfig) {
        $this->_scopeConfig = $scopeConfig;
    }

    public function afterToHtml(AbstractBlock $subject, $result)
    {
        if ($subject->getNameInLayout() === self::BLOCK_NAME && $this->_scopeConfig->getValue(self::class)) {
            return '';
        }

        return $result;
    }
}

Olduğu gibi Smartie gelen cevap I içine zinciri daha da yukarıya eklentisi çalıştı \Magento\Framework\View\Layout\Builder::buildbir ile afterBuild()yöntemle ama bu çünkü sonsuz bir özyineleme yönelen \Magento\Framework\View\Layout::getBlockve \Magento\Framework\View\Layout::unsetElementher iki çağrı \Magento\Framework\View\Layout\Builder::buildtekrar.


2

Düzendeki "blok" düğümünün "ifconfig" özelliği, bloğu mağaza yapılandırmasındaki değere bağlamanızı sağlar.

"ifconfig" işlemesi \Magento\Framework\View\Layout\GeneratorPool::buildStructure


Yine de "referenceBlock" ile çalışmaz. Yalnızca yeni bir blok eklediğinizde çalışır.
Nikita Abrashnev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.