Creating your own XML module configuration file

In Magento 1.x, it was possible to use the .xml file to include custom configuration options that might be necessary for an extension. This is no longer possible with Magento 2 because the XML files are all validated against a schema and anything other than predefined options are not allowed. To solve this, it is possible to generate your own custom XML file to set up the parameters that you need. This also allows other extensions to define settings as the output is generated from all modules that have this file configured.

Getting ready

In order to use your own XML configuration file, it is important that you generate a valid schema (XSD) file that will be used to validate the XML files when they are merged.

How to do it…

The following steps show you how to define a custom XML configuration file for your module:

  1. First, we create the Reader for the XML file and define the name of the file that should be read from all modules:

    Model/Sample/Reader.php

    <?php
    namespace GenmatoSampleModelSample;
    
    use MagentoFrameworkConfigReaderFilesystem;
    use MagentoFrameworkConfigFileResolverInterface;
    use MagentoFrameworkConfigConverterInterface;
    use GenmatoSampleModelSampleSchemaLocator;
    use MagentoFrameworkConfigValidationStateInterface;
    
    class Reader extends Filesystem
    {
      protected $_idAttributes = [
        '/table/row' => 'id',
        '/table/row/column' => 'id',
      ];
    
      /**
      * @param FileResolverInterface $fileResolver
      * @param ConverterInterface $converter
      * @param SchemaLocator $schemaLocator
      * @param ValidationStateInterface $validationState
      * @param string $fileName
      * @param array $idAttributes
      * @param string $domDocumentClass
      * @param string $defaultScope
      */
      public function __construct(
        FileResolverInterface $fileResolver,
        ConverterInterface $converter,
        SchemaLocator $schemaLocator,
        ValidationStateInterface $validationState,
        $fileName = 'sample.xml',
        $idAttributes = [],
        $domDocumentClass = 'MagentoFrameworkConfigDom',
        $defaultScope = 'global'
      ) {
        parent::__construct(
          $fileResolver,
          $converter,
          $schemaLocator,
          $validationState,
          $fileName,
          $idAttributes,
          $domDocumentClass,
          $defaultScope
        );
      }
    }
  2. To validate the schema, the Reader must know where to find the schema file:

    Model/Sample/SchemaLocator.php

    <?php
    namespace GenmatoSampleModelSample;
    
    use MagentoFrameworkConfigSchemaLocatorInterface;
    use MagentoFrameworkConfigDomUrnResolver;
    
    class SchemaLocator implements SchemaLocatorInterface
    {
      /** @var UrnResolver */
      protected $urnResolver;
    
      public function __construct(UrnResolver $urnResolver)
      {
        $this->urnResolver = $urnResolver;
      }
    
      /**
      * Get path to merged config schema
      *
      * @return string
      */
      public function getSchema()
      {
        return $this->urnResolver->getRealPath('urn:genmato:module:Genmato_Sample:/etc/sample.xsd');
      }
    
      /**
      * Get path to pre file validation schema
      *
      * @return string
      */
      public function getPerFileSchema()
      {
        return $this->urnResolver->getRealPath('urn:genmato:module:Genmato_Sample:/etc/sample.xsd');
      }
    }
  3. A single class is used to get the merged data and cache the XML:

    Model/Sample/Data.php

    <?php
    namespace GenmatoSampleModelSample;
    
    use MagentoFrameworkConfigDataScoped;
    use GenmatoSampleModelSampleReader;
    use MagentoFrameworkConfigScopeInterface;
    use MagentoFrameworkConfigCacheInterface;
    
    class Data extends Scoped
    {
      /**
      * Scope priority loading scheme
      *
      * @var array
      */
      protected $_scopePriorityScheme = ['global'];
    
      /**
      * @param Reader $reader
      * @param ScopeInterface $configScope
      * @param CacheInterface $cache
      * @param string $cacheId
      */
      public function __construct(
        Reader $reader,
        ScopeInterface $configScope,
        CacheInterface $cache,
        $cacheId = 'sample_config_cache'
      ) {
        parent::__construct($reader, $configScope, $cache, $cacheId);
      }
    }
  4. Add the XSD schema file:

    etc/sample.xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="table">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="row" maxOccurs="unbounded" minOccurs="0">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="column" maxOccurs="unbounded" minOccurs="0">
                    <xs:complexType>
                      <xs:sequence>
                        <xs:element type="xs:string" name="label">
                          <xs:annotation>
                            <xs:documentation>from first xml from second xmlthey apear in both xmls with the same path and id and second one overrides the value for `attr1` from first xml  from first xml</xs:documentation>
                          </xs:annotation>
                        </xs:element>
                      </xs:sequence>
                      <xs:attribute type="xs:string" name="id" use="optional"/>
                      <xs:attribute type="xs:byte" name="sort" use="optional"/>
                      <xs:attribute type="xs:string" name="attr1" use="optional"/>
                      <xs:attribute type="xs:string" name="disabled" use="optional"/>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
                <xs:attribute type="xs:string" name="id" use="optional"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  5. Add the configuration file for your module:

    etc/sample.xml

    <?xml version="1.0"?>
    <table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:genmato:module:Genmato_Sample:/etc/sample.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>
  6. Get and display the merged data: (This is optional; in this example, we display the data through a frontend route.)

    Controller/Index/Sample.php

    <?php
    namespace GenmatoSampleControllerIndex;
    
    use MagentoFrameworkAppActionAction;
    use MagentoFrameworkAppActionContext;
    use MagentoFrameworkViewResultPageFactory;
    use GenmatoSampleModelSampleDataFactory;
    
    class Sample extends Action
    {
      /**
      * @var PageFactory
      */
      private $resultPageFactory;
    
      /** @var  DataFactory $dataReader */
      private $dataReader;
    
      /**
      * @param Context $context
      * @param PageFactory $resultPageFactory
      * @param DataFactory $dataReader
      */
      public function __construct(
        Context $context,
        PageFactory $resultPageFactory,
        DataFactory $dataReader
      )
      {
        $this->dataReader = $dataReader;
        parent::__construct($context);
      }
    
      /**
      * Renders Sample
      */
      public function execute()
      {
        $myConfig = $this->dataReader->create();
        print_r($myConfig->get());
      }
    }
  7. Refresh the cache using the following command:
    bin/magento cache:clean
    
  8. Now you can check the result data using the following command:

    http://example.com/sample/index/sample/

How it works…

The configuration reader defines the file that is used in the ($fileName = 'sample.xml') constructor. Make sure that the filename used is unique; otherwise, configuration data from another module will be merged and validation will fail as it won't match the schema that you defined. A solution could be to use <vendor>_<module>.xml as the filename.

In the constructor, SchemaLocator is also defined; this will define the schema (XSD file) that is used to validate the XML. To be able to get the schema file independent from where the module is installed (vendor/ or app/code), the schema location is built from the defined URN: urn:genmato:module:Genmato_Sample:/etc/sample.xsd. This URN is parsed and translated to the directory where the module is installed, which is done through ComponentRegistrar, and the module location is registered in registration.php as described in Chapter 7, Creating Magento 2 Extensions – the Basics.

It is possible to get all data using the read() method on the Reader class, this will result in re-reading and merging all XML files, which will impact every request. This can delay the website; therefore, the Data class is added. Here, Reader is injected through the constructor. To get the data, you can call the get() method of the Data class. This will read and merge all XML files if they are not cached and return the cached version when available. If you don't supply an argument to the get() method, it will return all data, but it's also possible to specify a node that you would like.

The Data class can be added everywhere that you need to get your configuration data; for this, you add GenmatoSampleModelSampleDataFactory to the constructor. This autogenerated class allows you to instantiate your configuration data class:

$myConfig = $this->dataReader->create();

This gets a value from the configuration:

$myConfig->get('<node>');
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.176.145