- PVSM.RU - https://www.pvsm.ru -
Компонент Symfony 2 Config предназначен для работы с конфигурационными файлами и предоставляет следующие возможности:
Официальная документация [1] по этому компоненту содержит подробную информацию по его использованию. А мы давайте посмотрим на то, как устроен этот компонент внутри.
Вот так выглядит диаграмма классов, которые описывают структуру конфигурации.
Назначение практически всех классов понятно из их названия. Отмечу только, что для построения дерева конфигурации используется нода ArrayNode
[2]. Если требуется, чтобы внутри ArrayNode
[2] размещались не просто предпоределенные ноды, а несколько других ArrayNode
[2], но с четко одинаковой предопределенной внутренней структурой, можно использовать PrototypedArrayNode
[3].
Для построения описания конфигурации используется класс SymfonyComponentConfigDefinitionBuilderTreeBuilder
[4] примерно вот таким способом:
<?php
use SymfonyComponentConfigDefinitionBuilderTreeBuilder;
use SymfonyComponentConfigDefinitionConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('acme_demo');
$rootNode
->children()
->arrayNode('entities')
->addDefaultsIfNotSet()
->prototype('scalar')->end()
->defaultValue(
array(
'AcmeBaseBundleEntityDefaultEntity1',
'AcmeBaseBundleEntityDefaultEntity2',
)
)
->end();
return $rootNode;
}
}
Структуру конфигурации не обязательно объявлять всю целиком в одном месте. Можно сделать это частями, а затем объединить части при помощи метода append
у NodeBuilder
[5].
Нормализацией называется приведение имен ключей нод и их значений, если потребуется, к каноническому виду. Фактически, сейчас нормализация используется только для того, чтобы привести ноды, описанные в xml в виде
<children>
<child>Значение потомка</child>
</children>
к виду
"children" => Array(
[0] => "Значение потомка"
)
Для нормализации нод вызывается метод normalize()
из SymfonyComponentConfigDefinitionNodeInterface
[6]. А кроме того, у SymfonyComponentConfigDefinitionBaseNode
[7] есть еще метод preNormalize
. Последний используется для приведения к общему виду ключей типа foo_bar
и foo-bar
.
Процесс финализации ноды выполняет действия, по подготовке ноды к чтению внутри конфигурации и проверки на соответствие заявленому типу и его правилам. Финализация выполянется методом finalizeValue
потомков BaseNode
[7]
Валидация данных выполняется как с помощью предопределенных методов NodeDefinition
[8] и его потомков вроде isRequired
, так и с помощью расширенной валидации, делегированной классу SymfonyComponentConfigDefinitionBuilderValidationBuilder
[9].
Правила объединения данных из нескольких частей содержатся в классе SymfonyComponentConfigDefinitionBuilderMergeBuilder
[10]. Делегирование ему проверок выполняется методом merge() класса NodeDefinition
[11]. Например, можно запретить переопределять значение выбранного ключа конфигурации другими конфигурационными файлами после того, как он был прочитан в первый раз.
Сам процесс валидации / нормализации / финализации конфигурации выглядит так:
$configs = array($config1, $config2); //Загруженные любым способом части конфигурации
$processor = new Processor(); // Процессор конфигурации
$configuration = new Configuration(); // Класс Configuration c правилами проверки (см. выше).
$processedConfiguration = $processor->processConfiguration(
$configuration,
$configs
);
Как нетрудно заметить, для самого процесса построения описания конфигурации TreeBuilder
[4] использует экземпляр класса SymfonyComponentConfigDefinitionBuilderNodeBuilder
[5]. Поэтому вы вполне можете определять свои типы нод для конфигурации. Для этого необходимо создать свой вариант реализации NodeInterface
[6] и своего потомка SymfonyComponentConfigDefinitionBuilderNodeDefinition
[11]. После чего просто вызвать метод setNodeClass
у NodeBuilder
[12].
Во всех подробностях процесс определения структуры конфигурации описан тут [13].
После того, как структура конфигурации построена, ее можно сдампить с помощью различных дамперов из пространства имен SymfonyComponentConfigDefinitionDumper
[14]. Сейчас там есть два варианта: YamlReferenceDumper
[15] и XmlReferenceDumper
[16]. Эти дамперы используются, например, когда вы вызываете с консоли ./bin/symfony config:dump-reference
(см. SymfonyBundleFrameworkBundleCommandConfigDumpReferenceCommand
[17])
SymfonyComponentConfigResourceResourceInterface
[18]). Понятие ресурса достаточно абстрактно. Им может быть как файл, так и любой другой источник данных. Например, таблица БД или поле в ней.SymfonyComponentConfigResourceCheckerInterface
[19]).SymfonyComponentConfigLoaderLoaderInterface
[20]).SymfonyComponentConfigLoaderLoaderResolverInterface
[21]).SymfonyComponentConfigLoaderDelegatingLoader
[22] позволяет загрузить ресурс, автоматически найдя необходимый загрузчик, перебирая массив переданных ресолверов.SymfonyComponentConfigFileLocator
[23]
Нужно сказать, что сам компонент Config не содержит конкретных реализаций загрузчиков. Он лишь предоставляет необходимые интерфейсы для их реализации. Причем способ загрузки и целевой контейнер для загруженных данных тоже не регламентирован. Если посмотреть на реализацию SymfonyComponentDependencyInjectionLoaderYamlFileLoader
[24], то видно, что конфигурация загружается прямо в контейнер.
Symfony Config позволяет кешировать загруженную конфигурацию с помощью класса SymfonyComponentConfigConfigCache
[25]:
<?php
use SymfonyComponentConfigConfigCache;
use SymfonyComponentConfigResourceFileResource;
$cachePath = __DIR__.'/cache/appSomeCacheFile.php';
// Режим отладки определяет, будут ли проверяться на изменения ресурсы, из которых строился кеш
$cacheFile = new ConfigCache($cachePath, true);
if (!$cacheFile->isFresh()) {
$configFiles = []; // Здесь имена файлов, из которых состоит конфигурация
$resources = array();
foreach ($configFiles as $cfgFile) {
// Здесь загружаем конфигурацию
// .....
// И добавляем ресурс в массив
$resources[] = new FileResource($cfgFile);
}
$code = '...'; //Здесь строим кэш из загруженных данных
//Пишем кеш. Рядом с файлом кеша запишется файл с метаданными со списком исходных ресурсов
$cacheFile->write($code, $resources);
}
// Подключаем файл кеша
require $cachePath;
Можно инкапсулировать алгоритм перестройки кеша, например, в класс, а затем воспользоваться SymfonyComponentConfigConfigCacheFactory
[26] вместо ConfigCache
для дальнейшей работы. ConfigCacheFactory
принимает в конструкторе callable
, который будет перестраивать кеш.
Компонент Symfony Config вполне можно использовать и без фреймворка. В качестве примера приведу небольшой кусочек кода, написанный уважаемым magickatt [27]:
<?php
// Загружаем специфичную для приложения конфигурацию
try {
$basepath = __DIR__ . '/config';
$configuration = Yaml::parse($basepath . '/config.yml');
} catch (InvalidArgumentException $exception) {
exit("Кажется, конфигурационный файл отсутствует");
}
// Используем ConfigurationInterface для работы с *.yml форматом
$yamlConfiguration = new Configuration();
// Обрабатываем конфигурационные файлы (объединяем один или больше файлов *.yml)
$processor = new Processor();
$configuration = $processor->processConfiguration(
$yamlConfiguration,
array($configuration) // Здесь может быть любое количество *.yml файлов
);
use SymfonyComponentConfigDefinitionConfigurationInterface;
use SymfonyComponentConfigDefinitionBuilderTreeBuilder;
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;
}
}
Автор: FractalizeR
Источник [28]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/219954
Ссылки в тексте:
[1] Официальная документация: http://symfony.com/doc/current/components/config/index.html
[2] ArrayNode
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/ArrayNode.php
[3] PrototypedArrayNode
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php
[4] SymfonyComponentConfigDefinitionBuilderTreeBuilder
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php
[5] NodeBuilder
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
[6] SymfonyComponentConfigDefinitionNodeInterface
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/NodeInterface.php
[7] SymfonyComponentConfigDefinitionBaseNode
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/BaseNode.php
[8] NodeDefinition
: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
[9] SymfonyComponentConfigDefinitionBuilderValidationBuilder
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Builder/ValidationBuilder.php
[10] SymfonyComponentConfigDefinitionBuilderMergeBuilder
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Builder/MergeBuilder.php
[11] NodeDefinition
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php
[12] NodeBuilder
: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php
[13] тут: http://symfony.com/doc/current/components/config/definition.html
[14] SymfonyComponentConfigDefinitionDumper
: https://github.com/symfony/symfony/tree/2.8/src/Symfony/Component/Config/Definition/Dumper
[15] YamlReferenceDumper
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php
[16] XmlReferenceDumper
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php
[17] SymfonyBundleFrameworkBundleCommandConfigDumpReferenceCommand
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpReferenceCommand.php
[18] SymfonyComponentConfigResourceResourceInterface
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Resource/ResourceInterface.php
[19] SymfonyComponentConfigResourceCheckerInterface
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/ResourceCheckerInterface.php
[20] SymfonyComponentConfigLoaderLoaderInterface
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Loader/LoaderInterface.php
[21] SymfonyComponentConfigLoaderLoaderResolverInterface
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Loader/LoaderResolverInterface.php
[22] SymfonyComponentConfigLoaderDelegatingLoader
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/Loader/DelegatingLoader.php
[23] SymfonyComponentConfigFileLocator
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/FileLocator.php
[24] SymfonyComponentDependencyInjectionLoaderYamlFileLoader
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
[25] SymfonyComponentConfigConfigCache
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/ConfigCache.php
[26] SymfonyComponentConfigConfigCacheFactory
: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Config/ConfigCacheFactory.php
[27] magickatt: https://gist.github.com/magickatt/bb7108d276bce430cf35#file-gistfile1-php
[28] Источник: https://habrahabr.ru/post/271417/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.