Magento 2: Remove block ขึ้นอยู่กับการตั้งค่า


13

ฉันพยายามที่จะยกเลิกการบล็อกจากหน้าบาง (ไม่ว่าจะเป็นส่วนหน้าหรือแบ็กเอนด์) trueแต่ถ้าเป็นธงตั้งค่าบางอย่างที่มีการตั้งค่า
ลองยกตัวอย่าง
ฉันต้องการลบบล็อกที่มีชื่อdashboardจากแผงควบคุมของผู้ดูแลระบบ

บล็อกถูกกำหนดในadminhtml_dashboard_index.xmlไฟล์จากMagento_Backendโมดูล:

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

ขอบคุณคำตอบของอดัมที่ฉันสามารถทำได้ในadminhtml_dashboard_index.xml

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

แต่ฉันต้องการที่จะใช้มันขึ้นบากและลบบล็อกนี้เท่านั้นถ้าการตั้งค่าการกำหนดค่าที่มีเส้นทางที่มีค่าdashboard/settings/remove เลย์เอาท์ xml นั้นยอดเยี่ยม แต่ฉันก็จะใช้วิธีสังเกตการณ์ด้วยเช่นกัน1


Marius คุณรู้หรือไม่ว่ามีเหตุการณ์เดียวกันนี้สำหรับ.xmlฉันหมายถึงฉันต้องการรันผู้สังเกตการณ์ของฉันหากเปิดใช้งานการกำหนดค่า
Keyur Shah

ถ้าคุณต้องการไปกับhelperชั้นเรียนดู/programming/47237179/magento-2-i-want-to-add-if-igconfig-in-override-block-xml?rq=1
Asrar

คำตอบ:


17

ฉันไม่สามารถหาวิธีทำสิ่งนี้ด้วยเลย์เอาต์ได้ แต่นี่เป็นตัวอย่างของวิธีที่คุณสามารถทำได้กับผู้สังเกตการณ์ (หากพวกเขาขยายเทมเพลตบล็อก) ...

สร้าง events.xml ของคุณใน etc / 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="view_block_abstract_to_html_before">
        <observer name="remove_block" instance="[Vendor]\[ModuleName]\Model\Observer\RemoveBlock" />
    </event>
</config>

สร้างผู้สังเกตการณ์

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

โดยพื้นฐานแล้ว _toHtml จะตรวจสอบว่ามีเทมเพลตหรือไม่ ถ้าไม่มีมันจะส่งคืน ''

แก้ไข

หลังจากขุดอีกฉันพบวิธีที่จะทำสิ่งนี้ต่อไปในห่วงโซ่

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

และผู้สังเกตการณ์ ...

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

สิ่งนี้อาจใช้งานได้ แต่สำหรับบล็อกที่ใช้แม่แบบเท่านั้น มันใช้กับตัวอย่างที่ฉันให้ไว้ แต่ก็ยังถ้ามีบล็อกที่ขยาย AbstractBlock และไม่ใช่บล็อกเทมเพลตสิ่งนี้จะไม่ทำงาน +1 สำหรับจุดเริ่มต้นที่ดี
Marius

คุณถูก. หลังจากขุดอีกฉันพบว่าคุณสามารถทำได้ก่อนหน้านี้ในกระบวนการ อัปเดตคำตอบแล้ว ฉันทิ้งต้นฉบับไว้ที่นั่นเพื่อการอ้างอิง
Smartie

ขอบคุณนี่เป็นคำตอบที่มีประโยชน์ ปัญหาคือมันหมายถึงลอจิกจะถูกไล่ออกในทุก ๆ หน้าโหลดเพราะมันใช้อีเวนต์ "layout_generate_blocks_after" คุณรู้วิธีการเรียกใช้ในการโหลดหน้าเว็บบางหน้าหรือไม่เช่นการโหลดหน้าหมวดหมู่ (เหตุการณ์คือ "catalog_controller_category_init_after" แต่ไม่สามารถเข้าถึงเค้าโครงได้)
อเล็กซ์

2
จริงๆ?! เราต้องทำผู้สังเกตการณ์เพื่อลบหรือไม่บล็อกตามเงื่อนไข? นี่ไร้สาระแค่พูด
slayerbleast

1
ผู้สังเกตการณ์ไม่ควรจัดการกับข้อมูลที่ฉันคิดว่า ...
อเล็กซ์

5

โดยปกติควรทำด้วย<action />แท็ก:

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

แก้ไข:

ปัญหาเดียวคือ unsetChild ยอมรับเฉพาะนามแฝง คุณไม่สามารถใช้ชื่อบล็อก

โซลูชันอื่น ๆ : เขียน Magento Framework ใหม่เพื่อให้สามารถใช้ ifconfig with remove = "true"

1- สร้างโมดูลของคุณเอง

2- เพิ่มไฟล์ใหม่เพื่อแทนที่วีโอไอพีกรอบ: (เช่น/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 - เพิ่มไฟล์ di.xml เพื่อแทนที่ไฟล์ magento:

<?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- ตอนนี้คุณสามารถใช้ ifconfig ในรูปแบบรวมกับการลบ:

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

ตัวอย่างนี้ใช้สำหรับบล็อก แต่คุณสามารถทำเช่นเดียวกันกับคอนเทนเนอร์หากคุณแทนที่เมธอด containerReference () ของ /Magento/Framework/View/Layout/Reader/Container.php


ฉันคิดว่าการเขียน Framework ใหม่เป็นทางออกที่ดีที่สุดไม่รู้ว่าเพราะเหตุใด magento จึงไม่มีสิ่งนี้ตามค่าเริ่มต้น
slayerbleast

3

จากหลักเกณฑ์ทางเทคนิค :

14.1 ค่าทั้งหมด (รวมถึงวัตถุ) ที่ส่งผ่านไปยังเหตุการณ์ต้องไม่ถูกแก้ไขในตัวสังเกตเหตุการณ์ ควรใช้ปลั๊กอินแทนการแก้ไขอินพุตหรือเอาต์พุตของฟังก์ชัน

14.3 เหตุการณ์ไม่ควรเปลี่ยนสถานะของวัตถุที่สังเกตได้

ดังนั้นนี่คือโซลูชันปลั๊กอินสำหรับสิ่งนี้:

ประกาศปลั๊กอิน:

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

กำหนดปลั๊กอิน:

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

เช่นเดียวกับในคำตอบของ Smartieฉันพยายามที่จะเพิ่มปลั๊กอินเข้าไปในโซ่\Magento\Framework\View\Layout\Builder::buildด้วยafterBuild()วิธีการ แต่สิ่งนี้จะนำไปสู่การเรียกซ้ำที่ไม่มีที่สิ้นสุดเพราะ\Magento\Framework\View\Layout::getBlockและ\Magento\Framework\View\Layout::unsetElementทั้งคู่โทร\Magento\Framework\View\Layout\Builder::buildอีกครั้ง


2

คุณลักษณะ "ifconfig" ของโหนด "บล็อก" ในโครงร่างช่วยให้คุณสามารถเชื่อมโยงบล็อกกับค่าในการกำหนดค่าร้านค้า

การประมวลผล "ifconfig" เกิดขึ้น \Magento\Framework\View\Layout\GeneratorPool::buildStructure


มันจะไม่ทำงานกับ "referenceBlock" มันจะทำงานเฉพาะเมื่อคุณเพิ่มบล็อกใหม่
Nikita Abrashnev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.