ฉันจะมีไฟล์ XML ที่กำหนดเองในโมดูลที่รวมเป็นหนึ่งใน Magento 2 ได้อย่างไร (MageStackDay คำถามลึกลับ 2)


22

MageStackDay โบนัสคำถามสำหรับ 500pts Bounty และความเป็นไปได้ในการชนะใบอนุญาต Z-Ray ฟรีเป็นเวลาหนึ่งปี สามารถอ่านข้อมูลเพิ่มเติม >> ที่นี่ <<

คำถามมีให้ / ได้รับแรงบันดาลใจจากนักพัฒนาหลัก Magento 2 Anton Kril

คำถาม:

ฉันกำลังสร้างส่วนขยายที่มีการกำหนดค่าแยกต่างหาก
ซึ่งหมายความว่าฉันไม่สามารถใช้config.xmlหรือroutes.xmlหรือfieldset.xmlหรือไฟล์อื่น ๆ ที่ magento config มี
ตัวอย่าง.

สมมติว่าฉันกำลังกำหนดค่า 'ตาราง' ที่มีแถวคอลัมน์ ฉันสามารถใช้ xml ด้านล่างนี้ (เรียกมันว่าtable.xml)

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="path/to/table.xsd">
    <row id="row1">
        <column id="col1" sort="10" attr1="val1">
            <label>Col 1</label>
        </column>
    </row>
    <row id="row2">
        <column id="col1" sort="10" attr1="val1">
            <label>Col 1</label>
        </column>
        <column id="col2" sort="20" disabled="true" attr1="val2" >
            <label>Col 2</label>
        </column>
        <column id="col3" sort="15" attr1="val1">
            <label>Col 3</label>
        </column>
    </row>
</table>

แต่ถ้ามีนามสกุลอื่น ๆtable.xmlฉันต้องการให้มันถูกเลือกโดยผู้อ่าน config และควรรวมไฟล์ xml 2 ไฟล์ขึ้นไป ฉันหมายถึงว่าไฟล์ที่สองมีลักษณะเช่นนี้

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="path/to/table.xsd">
    <row id="row1">
        <column id="col2" sort="10" attr1="val2">
            <label>Col 2</label>
        </column>
    </row>
    <row id="row2">
        <column id="col1" sort="10" attr1="val5" />
    </row>
</table>

ผลลัพธ์จะเป็นว่าคอลัมน์ที่สองถูกเพิ่มในแถวแรกและค่าสำหรับattr1ถูกเขียนทับโดย xml ที่สอง:

<table ....>
    <row id="row1">
        <column id="col1" sort="10" attr1="val1"> <!-- from first xml -->
            <label>Col 1</label>
        </column>
        <column id="col2" sort="10" attr1="val2"><!-- from second xml-->
            <label>Col 2</label>
        </column>
    </row>
    <row id="row2">
        <column id="col1" sort="10" attr1="val5"><!--they apear in both xmls with the same path and id and second one overrides the value for `attr1`-->
            <label>Col 1</label>
        </column>
        <column id="col2" sort="20" disabled="true" attr1="val2"><!-- from first xml -->
            <label>Col 2</label>
        </column>
        <column id="col3" sort="15" attr1="val1"><!-- from first xml -->
            <label>Col 3</label>
        </column>
    </row>
</table>

ใน Magento 1 ฉันสามารถทำได้เพียงแค่โทรหา

 $merged = Mage::getConfig()->loadModulesConfiguration('table.xml')
            ->applyExtends();

ฉันจะทำเช่นเดียวกันสำหรับ Magento 2 ได้อย่างไร

คำตอบ:


15

ใน Magento 2 นี้จัดการโดย\Magento\Framework\Config\Reader\Filesystemชั้นเรียน คลาสนี้อนุญาตให้คุณระบุไฟล์ xml ที่คุณต้องการผสาน

ส่วนต่อไปนี้จะรวมไฟล์ทั้งหมดที่พบในโมดูลที่มีอยู่และรวมเอาท์พุท (ตัวอย่างจาก\Magento\Framework\Config\Reader\Filesystem)

/**
 * Load configuration scope
 *
 * @param string|null $scope
 * @return array
 */
public function read($scope = null)
{
    $scope = $scope ?: $this->_defaultScope;
    $fileList = $this->_fileResolver->get($this->_fileName, $scope);
    if (!count($fileList)) {
        return [];
    }
    $output = $this->_readFiles($fileList);

    return $output;
}

/**
 * Read configuration files
 *
 * @param array $fileList
 * @return array
 * @throws \Magento\Framework\Exception
 */
protected function _readFiles($fileList)
{
    /** @var \Magento\Framework\Config\Dom $configMerger */
    $configMerger = null;
    foreach ($fileList as $key => $content) {
        try {
            if (!$configMerger) {
                $configMerger = $this->_createConfigMerger($this->_domDocumentClass, $content);
            } else {
                $configMerger->merge($content);
            }
        } catch (\Magento\Framework\Config\Dom\ValidationException $e) {
            throw new \Magento\Framework\Exception("Invalid XML in file " . $key . ":\n" . $e->getMessage());
        }
    }
    if ($this->_isValidated) {
        $errors = [];
        if ($configMerger && !$configMerger->validate($this->_schemaFile, $errors)) {
            $message = "Invalid Document \n";
            throw new \Magento\Framework\Exception($message . implode("\n", $errors));
        }
    }

    $output = [];
    if ($configMerger) {
        $output = $this->_converter->convert($configMerger->getDom());
    }
    return $output;
}

ในโซลูชันที่ฉันสร้างคลาสข้างต้นถูกขยายเพื่อจัดหาไฟล์ xml ที่จำเป็นและระบุตำแหน่งที่สามารถตรวจสอบไฟล์ xsd (ดูที่https://github.com/Genmato/MageStackTableสำหรับตัวอย่างที่สมบูรณ์):

namespace Genmato\TableXml\Model\Table;

class Reader extends \Magento\Framework\Config\Reader\Filesystem
{
    protected $_idAttributes = [
        '/table/row' => 'id',
        '/table/row/column' => 'id',
    ];

    /**
     * @param \Magento\Framework\Config\FileResolverInterface $fileResolver
     * @param \Magento\Framework\Config\ConverterInterface $converter
     * @param \Genmato\TableXml\Model\Table\SchemaLocator $schemaLocator
     * @param \Magento\Framework\Config\ValidationStateInterface $validationState
     * @param string $fileName
     * @param array $idAttributes
     * @param string $domDocumentClass
     * @param string $defaultScope
     */
    public function __construct(
        \Magento\Framework\Config\FileResolverInterface $fileResolver,
        \Magento\Framework\Config\ConverterInterface $converter,
        \Genmato\TableXml\Model\Table\SchemaLocator $schemaLocator,
        \Magento\Framework\Config\ValidationStateInterface $validationState,
        $fileName = 'table.xml',
        $idAttributes = [],
        $domDocumentClass = 'Magento\Framework\Config\Dom',
        $defaultScope = 'global'
    ) {
        parent::__construct(
            $fileResolver,
            $converter,
            $schemaLocator,
            $validationState,
            $fileName,
            $idAttributes,
            $domDocumentClass,
            $defaultScope
        );
    }

ในการรับข้อมูลที่ผสานคุณสามารถโทร:

$output = $this->_objectManager->get('Genmato\TableXml\Model\Table\Reader')->read();

เอาต์พุตจะเป็นตัวแทนอาร์เรย์ของ xml ที่ผสาน

แก้ไข:

เพื่อทดสอบวิธีการอ่านไฟล์ฉันได้สร้างตัวอย่างการทำงาน (ดูhttps://github.com/Genmato/MageStackTable ) อัปเดตคำตอบด้วยบิลด์โซลูชัน


วลาดิเมียร์ก่อนหน้านี้วันนี้ฉันเห็นรุ่นคำตอบก่อนหน้าของคุณพร้อมDomตัวอย่างชั้น ฉันเริ่มทำงานโดยใช้คำตอบในReaderชั้นเรียน ในระหว่างนี้ฉันได้รีเฟรชหน้าคำถามและตระหนักว่าคุณทำอย่างนั้น :-) +1
Wojtek Naruniec

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

Marius ขอบคุณ! จะปล่อยให้โมดูลพร้อมใช้งานบน GitHub
Vladimir Kerkhoff
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.