Briefly about the architecture of the Symfony Config component

  • Tutorial


The Symfony 2 Config component is designed to work with configuration files and provides the following features:

  • Support tree configuration
  • Abstraction of the components of the configuration from which it is loaded (resources, resource loaders, etc.)
  • Support for an arbitrary number of configuration components and some assembly and merging rules
  • Caching the read configuration and automatically rebuilding it when changing one of the source files
  • Validation of the configuration according to various rules and detailed information about parsing errors

The official documentation for this component contains detailed information on its use. And let's look at how this component is arranged inside.

Defining a configuration structure


Types of configuration keys


Here is the class diagram that describes the configuration structure.

The purpose of almost all classes is clear from their name. I only note that a node is used to build the configuration tree ArrayNode. If you want to place inside ArrayNodenot just predefined nodes, but several others ArrayNode, but with a clearly identical predetermined internal structure, you can use it PrototypedArrayNode.

To build a configuration description, a class is used in Symfony\Component\Config\Definition\Builder\TreeBuilderapproximately this way:

root('acme_demo');
        $rootNode
            ->children()
            ->arrayNode('entities')
            ->addDefaultsIfNotSet()
            ->prototype('scalar')->end()
            ->defaultValue(
                array(
                    'Acme\BaseBundle\Entity\DefaultEntity1',
                    'Acme\BaseBundle\Entity\DefaultEntity2',
                )
            )
            ->end();
        return $rootNode;
    }
}

The configuration structure does not have to be declared all in one place. You can do this in parts, and then combine the parts using the appendy method NodeBuilder.

Normalization


Normalization is the reduction of node key names and their values, if necessary, to a canonical form. In fact, now normalization is used only to bring the nodes described in xml as

Значение потомка

to mind
    "children" => Array(
        [0] => "Значение потомка"
    )

To normalize the nodes, the method normalize()from is Symfony\Component\Config\Definition\NodeInterfacecalled. And besides, Symfony\Component\Config\Definition\BaseNodethere is another method preNormalize. The latter is used to generalize keys of type foo_barand foo-bar.

Finalization


The node finalization process takes steps to prepare the node for reading inside the configuration and check for compliance with the declared type and its rules. Finalization is performed using the finalizeValuedescendant method. Data validation is performed using both predefined methods and its descendants, sort of , as well as using extended validation delegated to the class . Rules for combining data from several parts are contained in the class . The delegation of checks to it is performed by the merge () method of the class . For example, you can prevent the value of the selected configuration key from being redefined by other configuration files after it has been read for the first time. The validation / normalization / finalization process itself looks like this:BaseNode

NodeDefinitionisRequiredSymfony\Component\Config\Definition\Builder\ValidationBuilder

Symfony\Component\Config\Definition\Builder\MergeBuilderNodeDefinition



$configs = array($config1, $config2); //Загруженные любым способом части конфигурации
$processor = new Processor(); // Процессор конфигурации
$configuration = new Configuration(); // Класс Configuration c правилами проверки (см. выше).
$processedConfiguration = $processor->processConfiguration(
    $configuration,
    $configs
);

Bilder


As you can see, for the process of constructing a configuration description, it TreeBuilderuses an instance of the class Symfony\Component\Config\Definition\Builder\NodeBuilder. Therefore, you can well define your types of nodes for configuration. To do this, you need to create your own implementation option NodeInterfaceand your descendant \Symfony\Component\Config\Definition\Builder\NodeDefinition. Then just call the setNodeClassy method NodeBuilder.

The process of determining the configuration structure is described in detail here .

Dumper


After the configuration structure is built, it can be dumped using various dampers from the namespace Symfony\Component\Config\Definition\Dumper. Now there are two options: YamlReferenceDumperand XmlReferenceDumper. These dampers are used, for example, when you call from the console ./bin/symfony config:dump-reference(see Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand)

Download configuration


Resources and downloaders



I must say that the Config component itself does not contain specific bootloader implementations. It only provides the necessary interfaces for their implementation. Moreover, the loading method and the target container for the downloaded data are also not regulated. If you look at the implementation Symfony\Component\DependencyInjection\Loader\YamlFileLoader, you can see that the configuration is loaded directly into the container.

Configuration caching


Symfony Config allows you to cache the loaded configuration using the class Symfony\Component\Config\ConfigCache:

isFresh()) {
    $configFiles = []; // Здесь имена файлов, из которых состоит конфигурация
    $resources = array();
    foreach ($configFiles as $cfgFile) {
        // Здесь загружаем конфигурацию
        // .....
        // И добавляем ресурс в массив
        $resources[] = new FileResource($cfgFile);
    }
    $code = '...'; //Здесь строим кэш из загруженных данных
    //Пишем кеш. Рядом с файлом кеша запишется файл с метаданными со списком исходных ресурсов
    $cacheFile->write($code, $resources);
}
// Подключаем файл кеша
require $cachePath;

You can encapsulate the cache rebuilding algorithm, for example, in a class, and then use Symfony\Component\Config\ConfigCacheFactoryinstead ConfigCachefor further work. ConfigCacheFactorytakes in a constructor callablethat will rebuild the cache.

Component usage example


The Symfony Config component can also be used without a framework. As an example, here is a small piece of code written by a reputable magickatt :

processConfiguration(
    $yamlConfiguration,
    array($configuration) // Здесь может быть любое количество *.yml файлов
);
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
class Configuration
{
    /**
     * @return TreeBuilder
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('arbitary');
        $rootNode->children()
            ->scalarNode('host')
            ->isRequired()
            ->cannotBeEmpty()
            ->end()
            ->scalarNode('username')
            ->isRequired()
            ->cannotBeEmpty()
            ->end()
            ->scalarNode('password')
            ->isRequired()
            ->cannotBeEmpty()
            ->end()
            ->booleanNode('bindRequiresDn')
            ->defaultTrue()
            ->end();
        return $treeBuilder;
    }
}

Also popular now: