Skip to content

Commit

Permalink
Merge 2cd2ae7 into d77511c
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-gribanov committed Feb 7, 2020
2 parents d77511c + 2cd2ae7 commit acd3c79
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 87 deletions.
230 changes: 153 additions & 77 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace GpsLab\Bundle\GeoIP2Bundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

Expand Down Expand Up @@ -49,24 +50,109 @@ public function getConfigTreeBuilder(): TreeBuilder
$root_node = $tree_builder->root('gpslab_geoip');
}

// normalize default_database from databases
$this->normalizeDefaultDatabase($root_node);
$this->normalizeRootConfigurationToDefaultDatabase($root_node);
$this->validateAvailableDefaultDatabase($root_node);
$this->allowGlobalLicense($root_node);
$this->allowGlobalLocales($root_node);
$this->validateDatabaseLocales($root_node);

$root_node->fixXmlConfig('locale');
$locales = $root_node->children()->arrayNode('locales');
$locales->prototype('scalar');
$locales
->treatNullLike([])
->defaultValue(['en']);

$root_node->children()->scalarNode('license');

$default_database = $root_node->children()->scalarNode('default_database');
$default_database->defaultValue('default');

$root_node->fixXmlConfig('database');
$root_node->append($this->getDatabaseNode());

return $tree_builder;
}

/**
* @return ArrayNodeDefinition
*/
private function getDatabaseNode(): ArrayNodeDefinition
{
$tree_builder = new TreeBuilder('databases');

if (method_exists($tree_builder, 'getRootNode')) {
// Symfony 4.2 +
$root_node = $tree_builder->getRootNode();
} else {
// Symfony 4.1 and below
$root_node = $tree_builder->root('databases');
}

$root_node->useAttributeAsKey('name');

/** @var ArrayNodeDefinition $database_node */
$database_node = $root_node->prototype('array');

$this->normalizeUrl($database_node);
$this->normalizePath($database_node);

$url = $database_node->children()->scalarNode('url');
$url->isRequired();

$this->validateURL($url);

$path = $database_node->children()->scalarNode('path');
$path->isRequired();

$database_node->fixXmlConfig('locale');
$locales = $database_node->children()->arrayNode('locales');
$locales->prototype('scalar');
$locales
->treatNullLike([])
->requiresAtLeastOneElement()
->defaultValue(['en']);

$database_node->children()->scalarNode('license');

$database_node->children()->scalarNode('edition');

return $root_node;
}

/**
* Normalize default_database from databases.
*
* @param NodeDefinition $root_node
*/
private function normalizeDefaultDatabase(NodeDefinition $root_node): void
{
$root_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
return
is_array($v) &&
!array_key_exists('default_database', $v) &&
array_key_exists('databases', $v) &&
is_array($v['databases']);
is_array($v['databases']) &&
$v['databases'];
})
->then(static function (array $v): array {
$keys = array_keys($v['databases']);
$v['default_database'] = reset($keys);

return $v;
});
}

// normalize databases root configuration to default_database
/**
* Normalize databases root configuration to default_database.
*
* @param NodeDefinition $root_node
*/
private function normalizeRootConfigurationToDefaultDatabase(NodeDefinition $root_node): void
{
$root_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
Expand All @@ -86,8 +172,15 @@ public function getConfigTreeBuilder(): TreeBuilder

return $v;
});
}

// default_database should be exists in databases
/**
* Validate that the default_database exists in the list of databases.
*
* @param NodeDefinition $root_node
*/
private function validateAvailableDefaultDatabase(NodeDefinition $root_node): void
{
$root_node
->validate()
->ifTrue(static function ($v): bool {
Expand All @@ -103,8 +196,16 @@ public function getConfigTreeBuilder(): TreeBuilder

throw new \InvalidArgumentException(sprintf('Undefined default database "%s". Available "%s" databases.', $v['default_database'], $databases));
});
}

// add license to databases config if not exists (allow use a global license for all databases)
/**
* Add a license option to the databases configuration if it does not exist.
* Allow use a global license for all databases.
*
* @param NodeDefinition $root_node
*/
private function allowGlobalLicense(NodeDefinition $root_node): void
{
$root_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
Expand All @@ -123,8 +224,16 @@ public function getConfigTreeBuilder(): TreeBuilder

return $v;
});
}

// add locales to databases config if not exists (allow use a global locales for all databases)
/**
* Add a locales option to the databases configuration if it does not exist.
* Allow use a global locales for all databases.
*
* @param NodeDefinition $root_node
*/
private function allowGlobalLocales(NodeDefinition $root_node): void
{
$root_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
Expand All @@ -143,66 +252,38 @@ public function getConfigTreeBuilder(): TreeBuilder

return $v;
});
}

// validate database locales
/**
* Validate database locales.
*
* @param NodeDefinition $root_node
*/
private function validateDatabaseLocales(NodeDefinition $root_node): void
{
$root_node
->validate()
->ifTrue(static function ($v): bool {
return
is_array($v) &&
array_key_exists('databases', $v) &&
is_array($v['databases']);
})
->then(static function (array $v): array {
foreach ($v['databases'] as $name => $database) {
if (!array_key_exists('locales', $database) || empty($database['locales'])) {
throw new \InvalidArgumentException(sprintf('The list of locales should not be empty in databases "%s".', $name));
}
->ifTrue(static function ($v): bool {
return is_array($v) && array_key_exists('databases', $v) && is_array($v['databases']);
})
->then(static function (array $v): array {
foreach ($v['databases'] as $name => $database) {
if (empty($database['locales'])) {
throw new \InvalidArgumentException(sprintf('The list of locales should not be empty in databases "%s".', $name));
}
}

return $v;
});

$root_node->fixXmlConfig('locale');
$locales = $root_node->children()->arrayNode('locales');
$locales->prototype('scalar');
$locales
->treatNullLike([])
->defaultValue(['en']);

$root_node->children()->scalarNode('license');

$default_database = $root_node->children()->scalarNode('default_database');
$default_database->defaultValue('default');

$root_node->fixXmlConfig('database');
$root_node->append($this->getDatabaseNode());

return $tree_builder;
return $v;
});
}

/**
* @return ArrayNodeDefinition
* Normalize url option from license key and edition id.
*
* @param NodeDefinition $database_node
*/
private function getDatabaseNode(): ArrayNodeDefinition
private function normalizeUrl(NodeDefinition $database_node): void
{
$tree_builder = new TreeBuilder('databases');

if (method_exists($tree_builder, 'getRootNode')) {
// Symfony 4.2 +
$root_node = $tree_builder->getRootNode();
} else {
// Symfony 4.1 and below
$root_node = $tree_builder->root('databases');
}

/** @var ArrayNodeDefinition $database_node */
$database_node = $root_node
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->prototype('array');

// normalize url from license and edition
$database_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
Expand All @@ -217,8 +298,15 @@ private function getDatabaseNode(): ArrayNodeDefinition

return $v;
});
}

// normalize path from edition
/**
* Normalize path option from edition id.
*
* @param NodeDefinition $database_node
*/
private function normalizePath(NodeDefinition $database_node): void
{
$database_node
->beforeNormalization()
->ifTrue(static function ($v): bool {
Expand All @@ -229,10 +317,15 @@ private function getDatabaseNode(): ArrayNodeDefinition

return $v;
});
}

$url = $database_node->children()->scalarNode('url');
$url->isRequired();
// url must be a valid URL
/**
* The url option must be a valid URL.
*
* @param NodeDefinition $url
*/
private function validateURL(NodeDefinition $url): void
{
$url
->validate()
->ifTrue(static function ($v): bool {
Expand All @@ -241,22 +334,5 @@ private function getDatabaseNode(): ArrayNodeDefinition
->then(static function (string $v): array {
throw new \InvalidArgumentException(sprintf('URL "%s" must be valid.', $v));
});

$path = $database_node->children()->scalarNode('path');
$path->isRequired();

$database_node->fixXmlConfig('locale');
$locales = $database_node->children()->arrayNode('locales');
$locales->prototype('scalar');
$locales
->treatNullLike([])
->requiresAtLeastOneElement()
->defaultValue(['en']);

$database_node->children()->scalarNode('license');

$database_node->children()->scalarNode('edition');

return $root_node;
}
}
28 changes: 18 additions & 10 deletions tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ public function getBadConfigs(): array
{
$return = [];
foreach (['/tmp/var/cache', null] as $cache_dir) {
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'databases' => null,
],
]];
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'databases' => [],
],
]];
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'license' => 'LICENSE',
Expand Down Expand Up @@ -151,6 +141,24 @@ public function getConfigs(): array
'default_database' => 'default',
'databases' => [],
]];
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'databases' => null,
],
], [
'databases' => [],
'locales' => ['en'],
'default_database' => 'default',
]];
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'databases' => [],
],
], [
'databases' => [],
'locales' => ['en'],
'default_database' => 'default',
]];
$return[] = [$cache_dir, [
'gpslab_geoip' => [
'license' => 'LICENSE',
Expand Down

0 comments on commit acd3c79

Please sign in to comment.