19

Scenario: I am a Magento 2 module developer. I want to create a configuration file in app/etc. I want this file to be "scoped" by area

app/etc/my_file.xml
app/etc/frontend/my_file.xml
app/etc/adminhtml/my_file.xml

In Magento 1 I'd just create a config.xmland be on my way. The area scoping happened in the XML file itself. However, Magento 2 approaches this very differently

In Magento 2, what class file(s?) should I create for reading these scoped configuration files. It's not clear from the Magento 2 source what "the right" way to do this is. The core code take multiple approaches, and none of them are marked with an @api method. This makes it difficult to know how to proceed with this common module developer task. As a secondary side-effect, it also makes it difficult to know how a Magento module developer should read from core configuration files.

On one hand, it seems like "the right" thing to do is create a file system reader object. For example, Magento seems to load the import.xml file with the following

#File: vendor/magento/module-import-export/Model/Import/Config/Reader.php
namespace Magento\ImportExport\Model\Import\Config;

class Reader extends \Magento\Framework\Config\Reader\Filesystem
{

    public function __construct(
        //...
        $fileName = 'import.xml',
        //...
    ) {
        parent::__construct(
            $fileResolver,
            $converter,
            $schemaLocator,
            $validationState,
            $fileName,
            $idAttributes,
            $domDocumentClass,
            $defaultScope
        );
    }
    //...
}        

The base Magento\Framework\Config\Reader\Filesystem class looks like it has code to resolve the area scope.

However some of the Magento configuration files seem to eschew this pattern. While there are readers for these files (event.xml in this example)

vendor/magento/framework/Event/Config/Reader.php

There's also "scoped data" classes that use these readers.

#File: vendor/magento/framework/Event/Config/Data.php
class Data extends \Magento\Framework\Config\Data\Scoped
{
    public function __construct(
        \Magento\Framework\Event\Config\Reader $reader,
        //...
    ) {
        parent::__construct($reader, $configScope, $cache, $cacheId);
    }
}

This makes it seem like the scoped reader classes are what a module developer should create. But not all configuration files have these scoped readers.

Is there a clear path for Magento 2 module developers to follow? Or is this just something Magento 2 module developers should approach in their own way, and the resulting chaos/non-standard-configuration-loading is just the cost of doing business?

The official documentation does a good job of covering some of the available classes, but nothing that reconciles the fact there's no clear guidance on which concrete implementation we're suppose to use, or if the expectation is every module decides how to do this on its own.

4

To create new configuration type, module developer should create a configuration type class that will be used by clients of configuration.

To make these type classes as simple as possible, all behavior of reading configuration files and caching data was moved to \Magento\Framework\Config\DataInterface with two reusable implementations:

  • \Magento\Framework\Config\Data - for configuration types that only make sense to be loaded in one scope (eav_attributes.xml only in global)
  • \Magento\Framework\Config\Data\Scoped - for configuration types that can be loaded on different scopes (events.xml - global and per-area)

Every configuration type is supposed to have pre-configured Config\DataInterface object. Configuration can be done either with Virtual Type or with inheritance.

Although module developer can technically inherit their configuration type from Config\DataInterface implementation, it's recommended not to extend from core classes. Always better to use composition.

Now \Magento\Framework\Config\Data and Data\Scoped only do caching and delegate configuration reading to \Magento\Framework\Config\ReaderInterface. ReaderInterface is supposed to provide valid configuration in format of PHP array for requested scope (if configuration is scoped). Multiple implementations of ReaderInterface are possible (for example read configuration from DB) but Magento only ships one generic reader: \Magento\Framework\Config\Reader\Filesystem.

\Magento\Framework\Config\Reader\Filesystem does all operations required for reading files from modular filesystem: read files, merge and validate.

Every Config\DataInterface is supposed to have separately configured instance of Config\ReaderInterface. As any instance in system, specific reader can be configured either with Virtual Type or with inheritance. Magento Documentation Describes all Filesystem dependencies.

Every element in this chain is optional (except for Config Type Class itself) and can be substituted with more specific implementation.

1

Looks like official documentation has answers to your question.

  • 1
    Thank you for responding, but I'm not sure that documentation does answer my question. It lists a number of interfaces (which is useful, +1 for that) that are available, but doesn't reconcile the fact none of the concrete implementations of those interfaces (Magento\Framework\Config\Data and Magento\Framework\App\Config) aren't marked with @api. If left with only that documentation I'd be under the assumption that, as a module developer, there no standard system for creating and reading configuration files, and that I can do whatever I want. That doesn't seem right. – Alan Storm Nov 29 '15 at 20:54
  • Can you describe cases when you need to read configuration for some other module? For me configuration reader is private api of module. – KAndy Nov 29 '15 at 21:02
  • If a developer wanted to contribute to Magento core. If a developer works on multiple modules, not all of which they control, and doesn't want to untangle a UML chart to read a value from a configuration file. See also -- most other PHP frameworks with a configuration system. Regardless, if the intention of the Magento 2 core team is that module configuration is a private and custom per module, that should be stated somewhere. – Alan Storm Nov 29 '15 at 21:06
  • Also also -- (slightly different/tangential) the System Configuration section in the backend of Magento -- building a feature based on an existing section's configuration. – Alan Storm Nov 29 '15 at 21:11
  • 2
    Any api that not annotated with @api is private in sense that if you use it then you responsible for backward compatibility/api changes issues. \Magento\Framework\Config\ReaderInterface have \@api annotation. – KAndy Nov 29 '15 at 21:34
0

There does not, at the time of this writing, appear to be a standard was of reading a merged configuration tree in Magento 2. Each module implements its own configuration reading classes, which means its up to each developer to decide how they want this merging to happen. While Magento offers some stock classes to do this, even among the core code the use of these classes is inconsistent.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.