Làm cách nào tôi có thể có tệp XML tùy chỉnh trong các mô-đun được hợp nhất như một trong Magento 2? (Câu hỏi bí ẩn MageStackDay 2)


22

Câu hỏi thưởng MageStackDay cho 500pts Bounty VÀ khả năng giành được giấy phép Z-Ray miễn phí trong một năm. Thông tin thêm có thể được tìm thấy >> tại đây <<

Các câu hỏi được cung cấp / lấy cảm hứng từ nhà phát triển cốt lõi Magento 2 Anton Kril.

Câu hỏi:

Tôi đang tạo một tiện ích mở rộng có một bộ cấu hình riêng biệt.
Điều này có nghĩa tôi không thể sử dụng config.xmlhoặc routes.xmlhoặc fieldset.xmlhoặc bất kỳ tập tin cấu hình xml khác Magento có.
Thí dụ.

Giả sử tôi đang xác định cấu hình 'bảng' có các hàng cột. Tôi có thể sử dụng xml này dưới đây. (gọi nó 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>

Nhưng nếu một phần mở rộng khác chứa table.xmltôi muốn nó được chọn bởi trình đọc cấu hình và 2 hoặc nhiều tệp xml sẽ được hợp nhất. Ý tôi là nếu tập tin thứ hai trông như thế này

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

kết quả sẽ là cột thứ hai được thêm vào hàng đầu tiên và giá trị cho attr1được ghi đè bởi xml thứ hai:

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

Trong Magento 1 tôi có thể thực hiện điều này chỉ bằng cách gọi

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

Làm thế nào tôi có thể làm tương tự cho Magento 2?

Câu trả lời:


15

Trong Magento 2, điều này được xử lý bởi \Magento\Framework\Config\Reader\Filesystemlớp. Lớp này cho phép bạn chỉ định tệp xml bạn muốn hợp nhất.

Phần sau đây sẽ hợp nhất tất cả các tệp được tìm thấy trong các mô-đun có sẵn và hợp nhất đầu ra (đoạn trích từ \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;
}

Trong giải pháp tôi đã tạo, lớp trên được mở rộng để cung cấp tệp xml cần thiết và chỉ định nơi có thể tìm thấy tệp xsd để xác thực (xem https://github.com/Genmato/MageStackTable để biết ví dụ hoàn chỉnh):

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

Để có được dữ liệu hợp nhất, bạn có thể gọi:

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

Đầu ra sau đó là một đại diện mảng của xml đã hợp nhất.

CHỈNH SỬA:

Để kiểm tra cách các tệp được đọc, tôi đã tạo một ví dụ hoạt động (xem https://github.com/Genmato/MageStackTable ). Cập nhật câu trả lời với giải pháp xây dựng.


Vladimir, đầu ngày hôm nay tôi đã thấy phiên bản trả lời trước của bạn với Domví dụ lớp. Tôi bắt đầu làm việc trên Readerlớp sử dụng câu trả lời . Trong lúc đó tôi đã làm mới trang câu hỏi và nhận ra bạn đã làm điều đó :-) +1
Wojtek Naruniec

Cảm ơn câu trả lời chi tiết đầy đủ và cho mô-đun POC từ github. Hãy để nó ở đó để tham khảo trong tương lai. Ở đây ... có một số tiền thưởng.
Marius

Marius, cảm ơn! Sẽ để lại mô-đun có sẵn trên GitHub.
Vladimir Kerkhoff
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.