[DIC] Better handling of enableable configurations
This commit is contained in:
parent
4bdfb92a35
commit
fde7585967
@ -91,10 +91,10 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('form')
|
||||
->info('form configuration')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->end()
|
||||
->arrayNode('csrf_protection')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('field_name')->defaultValue('_token')->end()
|
||||
->end()
|
||||
@ -109,7 +109,7 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('esi')
|
||||
->info('esi configuration')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
@ -121,7 +121,7 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('router_proxy')
|
||||
->info('proxy configuration for the HTTP content renderer')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('path')->defaultValue('/_proxy')->end()
|
||||
->end()
|
||||
@ -136,7 +136,7 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('profiler')
|
||||
->info('profiler configuration')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->booleanNode('only_exceptions')->defaultFalse()->end()
|
||||
->booleanNode('only_master_requests')->defaultFalse()->end()
|
||||
@ -176,8 +176,10 @@ class Configuration implements ConfigurationInterface
|
||||
->scalarNode('https_port')->defaultValue(443)->end()
|
||||
->scalarNode('strict_requirements')
|
||||
->info(
|
||||
'set to false to disable exceptions when a route is '.
|
||||
'generated with invalid parameters (and return null instead)'
|
||||
"set to true to throw an exception when a parameter does not match the requirements\n".
|
||||
"set to false to disable exceptions when a parameter does not match the requirements (and return null instead)\n".
|
||||
"set to null to disable parameter checks against requirements\n".
|
||||
"'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production"
|
||||
)
|
||||
->defaultTrue()
|
||||
->end()
|
||||
@ -367,7 +369,7 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('translator')
|
||||
->info('translator configuration')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('fallback')->defaultValue('en')->end()
|
||||
->end()
|
||||
@ -382,7 +384,7 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('validation')
|
||||
->info('validation configuration')
|
||||
->canBeDisabled()
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('cache')->end()
|
||||
->booleanNode('enable_annotations')->defaultFalse()->end()
|
||||
|
@ -81,37 +81,23 @@ class FrameworkExtension extends Extension
|
||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['form']) && !empty($config['form']['enabled'])) {
|
||||
if ($this->isConfigEnabled($container, $config['form'])) {
|
||||
$this->registerFormConfiguration($config, $container, $loader);
|
||||
$config['validation']['enabled'] = true;
|
||||
}
|
||||
|
||||
if (!empty($config['validation']['enabled'])) {
|
||||
$this->registerValidationConfiguration($config['validation'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['esi'])) {
|
||||
$this->registerEsiConfiguration($config['esi'], $loader);
|
||||
}
|
||||
|
||||
if (isset($config['router_proxy'])) {
|
||||
$this->registerRouterProxyConfiguration($config['router_proxy'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['profiler'])) {
|
||||
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['router'])) {
|
||||
$this->registerRouterConfiguration($config['router'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['templating'])) {
|
||||
$this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['translator'])) {
|
||||
$this->registerTranslatorConfiguration($config['translator'], $container);
|
||||
$this->registerValidationConfiguration($config['validation'], $container, $loader);
|
||||
$this->registerEsiConfiguration($config['esi'], $container, $loader);
|
||||
$this->registerRouterProxyConfiguration($config['router_proxy'], $container, $loader);
|
||||
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
|
||||
$this->registerTranslatorConfiguration($config['translator'], $container);
|
||||
|
||||
if (isset($config['router'])) {
|
||||
$this->registerRouterConfiguration($config['router'], $container, $loader);
|
||||
}
|
||||
|
||||
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
|
||||
@ -161,7 +147,7 @@ class FrameworkExtension extends Extension
|
||||
private function registerFormConfiguration($config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
$loader->load('form.xml');
|
||||
if (isset($config['csrf_protection'])) {
|
||||
if ($this->isConfigEnabled($container, $config['csrf_protection'])) {
|
||||
if (!isset($config['session'])) {
|
||||
throw new \LogicException('CSRF protection needs that sessions are enabled.');
|
||||
}
|
||||
@ -170,36 +156,44 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
$loader->load('form_csrf.xml');
|
||||
|
||||
$container->setParameter('form.type_extension.csrf.enabled', $config['csrf_protection']['enabled']);
|
||||
$container->setParameter('form.type_extension.csrf.enabled', true);
|
||||
$container->setParameter('form.type_extension.csrf.field_name', $config['csrf_protection']['field_name']);
|
||||
} else {
|
||||
$container->setParameter('form.type_extension.csrf.enabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the ESI configuration.
|
||||
*
|
||||
* @param array $config An ESI configuration array
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
* @param array $config A proxy configuration array
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
*/
|
||||
private function registerEsiConfiguration(array $config, XmlFileLoader $loader)
|
||||
private function registerEsiConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
if (!empty($config['enabled'])) {
|
||||
$loader->load('esi.xml');
|
||||
if (!$this->isConfigEnabled($container, $config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader->load('esi.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the router proxy configuration.
|
||||
*
|
||||
* @param array $config A proxy configuration array
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
* @param array $config A proxy configuration array
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
*/
|
||||
private function registerRouterProxyConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
if (!empty($config['enabled'])) {
|
||||
$loader->load('proxy.xml');
|
||||
$container->setParameter('http_content_renderer.proxy_path', $config['path']);
|
||||
if (!$this->isConfigEnabled($container, $config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader->load('proxy.xml');
|
||||
$container->setParameter('http_content_renderer.proxy_path', $config['path']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +252,7 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
if (!$config['enabled']) {
|
||||
if (!$this->isConfigEnabled($container, $config)) {
|
||||
$container->getDefinition('profiler')->addMethodCall('disable', array());
|
||||
}
|
||||
}
|
||||
@ -530,61 +524,63 @@ class FrameworkExtension extends Extension
|
||||
*/
|
||||
private function registerTranslatorConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
if (!empty($config['enabled'])) {
|
||||
// Use the "real" translator instead of the identity default
|
||||
$container->setAlias('translator', 'translator.default');
|
||||
$translator = $container->findDefinition('translator.default');
|
||||
$translator->addMethodCall('setFallbackLocale', array($config['fallback']));
|
||||
if (!$this->isConfigEnabled($container, $config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Discover translation directories
|
||||
$dirs = array();
|
||||
if (class_exists('Symfony\Component\Validator\Validator')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Validator\Validator');
|
||||
// Use the "real" translator instead of the identity default
|
||||
$container->setAlias('translator', 'translator.default');
|
||||
$translator = $container->findDefinition('translator.default');
|
||||
$translator->addMethodCall('setFallbackLocale', array($config['fallback']));
|
||||
|
||||
$dirs[] = dirname($r->getFilename()).'/Resources/translations';
|
||||
}
|
||||
if (class_exists('Symfony\Component\Form\Form')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Form\Form');
|
||||
// Discover translation directories
|
||||
$dirs = array();
|
||||
if (class_exists('Symfony\Component\Validator\Validator')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Validator\Validator');
|
||||
|
||||
$dirs[] = dirname($r->getFilename()).'/Resources/translations';
|
||||
}
|
||||
if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException');
|
||||
$dirs[] = dirname($r->getFilename()).'/Resources/translations';
|
||||
}
|
||||
if (class_exists('Symfony\Component\Form\Form')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Form\Form');
|
||||
|
||||
$dirs[] = dirname($r->getFilename()).'/../../Resources/translations';
|
||||
}
|
||||
$overridePath = $container->getParameter('kernel.root_dir').'/Resources/%s/translations';
|
||||
foreach ($container->getParameter('kernel.bundles') as $bundle => $class) {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
if (is_dir($dir = sprintf($overridePath, $bundle))) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
}
|
||||
if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/translations')) {
|
||||
$dirs[] = dirname($r->getFilename()).'/Resources/translations';
|
||||
}
|
||||
if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
|
||||
$r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException');
|
||||
|
||||
$dirs[] = dirname($r->getFilename()).'/../../Resources/translations';
|
||||
}
|
||||
$overridePath = $container->getParameter('kernel.root_dir').'/Resources/%s/translations';
|
||||
foreach ($container->getParameter('kernel.bundles') as $bundle => $class) {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
if (is_dir($dir = sprintf($overridePath, $bundle))) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
}
|
||||
if (is_dir($dir = $container->getParameter('kernel.root_dir').'/Resources/translations')) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
|
||||
// Register translation resources
|
||||
if ($dirs) {
|
||||
foreach ($dirs as $dir) {
|
||||
$container->addResource(new DirectoryResource($dir));
|
||||
}
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->filter(function (\SplFileInfo $file) {
|
||||
return 2 === substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename());
|
||||
})
|
||||
->in($dirs)
|
||||
;
|
||||
// Register translation resources
|
||||
if ($dirs) {
|
||||
foreach ($dirs as $dir) {
|
||||
$container->addResource(new DirectoryResource($dir));
|
||||
}
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->filter(function (\SplFileInfo $file) {
|
||||
return 2 === substr_count($file->getBasename(), '.') && preg_match('/\.\w+$/', $file->getBasename());
|
||||
})
|
||||
->in($dirs)
|
||||
;
|
||||
|
||||
foreach ($finder as $file) {
|
||||
// filename is domain.locale.format
|
||||
list($domain, $locale, $format) = explode('.', $file->getBasename(), 3);
|
||||
$translator->addMethodCall('addResource', array($format, (string) $file, $locale, $domain));
|
||||
}
|
||||
foreach ($finder as $file) {
|
||||
// filename is domain.locale.format
|
||||
list($domain, $locale, $format) = explode('.', $file->getBasename(), 3);
|
||||
$translator->addMethodCall('addResource', array($format, (string) $file, $locale, $domain));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,6 +594,10 @@ class FrameworkExtension extends Extension
|
||||
*/
|
||||
private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
if (!$this->isConfigEnabled($container, $config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader->load('validator.xml');
|
||||
|
||||
$container->setParameter('validator.translation_domain', $config['translation_domain']);
|
||||
|
@ -16,46 +16,41 @@ use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getTestConfigTreeData
|
||||
*/
|
||||
public function testConfigTree($options, $results)
|
||||
public function testDefaultConfig()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(array());
|
||||
$config = $processor->processConfiguration($configuration, array($options));
|
||||
$config = $processor->processConfiguration(new Configuration(), array(array('secret' => 's3cr3t')));
|
||||
|
||||
$this->assertEquals($results, $config);
|
||||
}
|
||||
|
||||
public function getTestConfigTreeData()
|
||||
{
|
||||
return array(
|
||||
array(array('secret' => 's3cr3t'), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
$this->assertEquals(
|
||||
array_merge(array('secret' => 's3cr3t'), self::getBundleDefaultConfig()),
|
||||
$config
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTestValidTrustedProxiesData
|
||||
*/
|
||||
public function testValidTrustedProxies($options, $results)
|
||||
public function testValidTrustedProxies($trustedProxies, $processedProxies)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(array());
|
||||
$config = $processor->processConfiguration($configuration, array($options));
|
||||
$config = $processor->processConfiguration($configuration, array(array(
|
||||
'secret' => 's3cr3t',
|
||||
'trusted_proxies' => $trustedProxies
|
||||
)));
|
||||
|
||||
$this->assertEquals($results, $config);
|
||||
$this->assertEquals($processedProxies, $config['trusted_proxies']);
|
||||
}
|
||||
|
||||
public function getTestValidTrustedProxiesData()
|
||||
{
|
||||
return array(
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('::1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1', '::1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1', '::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => null), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => false), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array()), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => '%kernel.debug%'), 'default_locale' => 'en', 'charset' => null)),
|
||||
array(array('127.0.0.1'), array('127.0.0.1')),
|
||||
array(array('::1'), array('::1')),
|
||||
array(array('127.0.0.1', '::1'), array('127.0.0.1', '::1')),
|
||||
array(null, array()),
|
||||
array(false, array()),
|
||||
array(array(), array()),
|
||||
);
|
||||
}
|
||||
|
||||
@ -66,7 +61,12 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(array());
|
||||
$config = $processor->processConfiguration($configuration, array(array('secret' => 's3cr3t', 'trusted_proxies' => 'Not an IP address')));
|
||||
$processor->processConfiguration($configuration, array(
|
||||
array(
|
||||
'secret' => 's3cr3t',
|
||||
'trusted_proxies' => 'Not an IP address'
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +76,55 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(array());
|
||||
$config = $processor->processConfiguration($configuration, array(array('secret' => 's3cr3t', 'trusted_proxies' => array('Not an IP address'))));
|
||||
$processor->processConfiguration($configuration, array(
|
||||
array(
|
||||
'secret' => 's3cr3t',
|
||||
'trusted_proxies' => array('Not an IP address')
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
protected static function getBundleDefaultConfig()
|
||||
{
|
||||
return array(
|
||||
'charset' => null,
|
||||
'trust_proxy_headers' => false,
|
||||
'trusted_proxies' => array(),
|
||||
'ide' => null,
|
||||
'default_locale' => 'en',
|
||||
'form' => array('enabled' => false),
|
||||
'csrf_protection' => array(
|
||||
'enabled' => false,
|
||||
'field_name' => '_token',
|
||||
),
|
||||
'esi' => array('enabled' => false),
|
||||
'router_proxy' => array(
|
||||
'enabled' => false,
|
||||
'path' => '/_proxy',
|
||||
),
|
||||
'profiler' => array(
|
||||
'enabled' => false,
|
||||
'only_exceptions' => false,
|
||||
'only_master_requests' => false,
|
||||
'dsn' => 'file:%kernel.cache_dir%/profiler',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'lifetime' => 86400,
|
||||
),
|
||||
'translator' => array(
|
||||
'enabled' => false,
|
||||
'fallback' => 'en',
|
||||
),
|
||||
'validation' => array(
|
||||
'enabled' => false,
|
||||
'enable_annotations' => false,
|
||||
'translation_domain' => 'validators',
|
||||
),
|
||||
'annotations' => array(
|
||||
'cache' => 'file',
|
||||
'file_cache_dir' => '%kernel.cache_dir%/annotations',
|
||||
'debug' => '%kernel.debug%',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
$container->loadFromExtension('framework', array(
|
||||
'secret' => 's3cr3t',
|
||||
'validation' => array(
|
||||
'enabled' => true,
|
||||
'enabled' => true,
|
||||
'enable_annotations' => true,
|
||||
),
|
||||
));
|
||||
|
@ -4,6 +4,9 @@ CHANGELOG
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added ArrayNodeDefinition::canBeEnabled() and ArrayNodeDefinition::canBeDisabled()
|
||||
to ease configuration when some sections are respectively disabled / enabled
|
||||
by default.
|
||||
* added a `normalizeKeys()` method for array nodes (to avoid key normalization)
|
||||
* added numerical type handling for config definitions
|
||||
* added convenience methods for optional configuration sections to ArrayNodeDefinition
|
||||
|
@ -214,16 +214,32 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
|
||||
/**
|
||||
* Adds an "enabled" boolean to enable the current section.
|
||||
*
|
||||
* By default, the section is disabled.
|
||||
* By default, the section is disabled. If any configuration is specified then
|
||||
* the node will be automatically enabled:
|
||||
*
|
||||
* enableableArrayNode: {enabled: true, ...} # The config is enabled & default values get overridden
|
||||
* enableableArrayNode: ~ # The config is enabled & use the default values
|
||||
* enableableArrayNode: true # The config is enabled & use the default values
|
||||
* enableableArrayNode: {other: value, ...} # The config is enabled & default values get overridden
|
||||
* enableableArrayNode: {enabled: false, ...} # The config is disabled
|
||||
* enableableArrayNode: false # The config is disabled
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function canBeEnabled()
|
||||
{
|
||||
$this
|
||||
->addDefaultsIfNotSet()
|
||||
->treatFalseLike(array('enabled' => false))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->beforeNormalization()
|
||||
->ifArray()
|
||||
->then(function($v) {
|
||||
$v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->booleanNode('enabled')
|
||||
->defaultFalse()
|
||||
@ -242,6 +258,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition
|
||||
public function canBeDisabled()
|
||||
{
|
||||
$this
|
||||
->addDefaultsIfNotSet()
|
||||
->treatFalseLike(array('enabled' => false))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->treatNullLike(array('enabled' => true))
|
||||
|
@ -79,18 +79,19 @@ class Processor
|
||||
$plural = $key.'s';
|
||||
}
|
||||
|
||||
$values = array();
|
||||
if (isset($config[$plural])) {
|
||||
$values = $config[$plural];
|
||||
} elseif (isset($config[$key])) {
|
||||
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
|
||||
// only one
|
||||
$values = array($config[$key]);
|
||||
} else {
|
||||
$values = $config[$key];
|
||||
}
|
||||
return $config[$plural];
|
||||
}
|
||||
|
||||
return $values;
|
||||
if (isset($config[$key])) {
|
||||
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
|
||||
// only one
|
||||
return array($config[$key]);
|
||||
}
|
||||
|
||||
return $config[$key];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
@ -25,19 +25,13 @@ class ArrayNodeTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* normalize() should protect against child values with no corresponding node
|
||||
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
|
||||
* @expectedExceptionMessage Unrecognized options "foo" under "root"
|
||||
*/
|
||||
public function testExceptionThrownOnUnrecognizedChild()
|
||||
{
|
||||
$node = new ArrayNode('root');
|
||||
|
||||
try {
|
||||
$node->normalize(array('foo' => 'bar'));
|
||||
$this->fail('An exception should have been throw for a bad child node');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', $e);
|
||||
$this->assertEquals('Unrecognized options "foo" under "root"', $e->getMessage());
|
||||
}
|
||||
$node->normalize(array('foo' => 'bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Config\Tests\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
|
||||
|
||||
@ -62,7 +63,10 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
public function testConcreteNodeSpecificOption()
|
||||
{
|
||||
$node = new ArrayNodeDefinition('root');
|
||||
$node->addDefaultsIfNotSet()->prototype('array');
|
||||
$node
|
||||
->addDefaultsIfNotSet()
|
||||
->prototype('array')
|
||||
;
|
||||
$node->getNode();
|
||||
}
|
||||
|
||||
@ -149,6 +153,50 @@ class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
$node->getNode();
|
||||
}
|
||||
|
||||
public function testEnabledNodeDefaults()
|
||||
{
|
||||
$node = new ArrayNodeDefinition('root');
|
||||
$node
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('foo')->defaultValue('bar')->end()
|
||||
;
|
||||
|
||||
$this->assertEquals(array('enabled' => false, 'foo' => 'bar'), $node->getNode()->getDefaultValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getEnableableNodeFixtures
|
||||
*/
|
||||
public function testTrueEnableEnabledNode($expected, $config, $message)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$node = new ArrayNodeDefinition('root');
|
||||
$node
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('foo')->defaultValue('bar')->end()
|
||||
;
|
||||
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$processor->process($node->getNode(), $config),
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
public function getEnableableNodeFixtures()
|
||||
{
|
||||
return array(
|
||||
array(array('enabled' => true, 'foo' => 'bar'), array(true), 'true enables an enableable node'),
|
||||
array(array('enabled' => true, 'foo' => 'bar'), array(null), 'null enables an enableable node'),
|
||||
array(array('enabled' => true, 'foo' => 'bar'), array(array('enabled' => true)), 'An enableable node can be enabled'),
|
||||
array(array('enabled' => true, 'foo' => 'baz'), array(array('foo' => 'baz')), 'any configuration enables an enableable node'),
|
||||
array(array('enabled' => false, 'foo' => 'baz'), array(array('foo' => 'baz', 'enabled' => false)), 'An enableable node can be disabled'),
|
||||
array(array('enabled' => false, 'foo' => 'bar'), array(false), 'false disables an enableable node'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getField($object, $field)
|
||||
{
|
||||
$reflection = new \ReflectionProperty($object, $field);
|
||||
|
@ -4,6 +4,7 @@ CHANGELOG
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added Extension::isConfigEnabled() to ease working with enableable configurations
|
||||
* added an Extension base class with sensible defaults to be used in conjunction
|
||||
with the Config component.
|
||||
* added PrependExtensionInterface (to be able to allow extensions to prepend
|
||||
|
@ -12,6 +12,8 @@
|
||||
namespace Symfony\Component\DependencyInjection\Extension;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
@ -62,26 +64,19 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
|
||||
*
|
||||
* @return string The alias
|
||||
*
|
||||
* @throws \BadMethodCallException When the extension name does not follow conventions
|
||||
* @throws BadMethodCallException When the extension name does not follow conventions
|
||||
*/
|
||||
public function getAlias()
|
||||
{
|
||||
$className = get_class($this);
|
||||
if (substr($className, -9) != 'Extension') {
|
||||
throw new \BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.');
|
||||
throw new BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.');
|
||||
}
|
||||
$classBaseName = substr(strrchr($className, '\\'), 1, -9);
|
||||
|
||||
return Container::underscore($classBaseName);
|
||||
}
|
||||
|
||||
final protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
|
||||
{
|
||||
$processor = new Processor();
|
||||
|
||||
return $processor->processConfiguration($configuration, $configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -104,4 +99,28 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
final protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
|
||||
{
|
||||
$processor = new Processor();
|
||||
|
||||
return $processor->processConfiguration($configuration, $configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @param array $config
|
||||
*
|
||||
* @return Boolean Whether the configuration is enabled
|
||||
*
|
||||
* @throws InvalidArgumentException When the config is not enableable
|
||||
*/
|
||||
protected function isConfigEnabled(ContainerBuilder $container, array $config)
|
||||
{
|
||||
if (!array_key_exists('enabled', $config)) {
|
||||
throw new InvalidArgumentException("The config array has no 'enabled' key.");
|
||||
}
|
||||
|
||||
return (Boolean) $container->getParameterBag()->resolveValue($config['enabled']);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Extension;
|
||||
|
||||
class ExtensionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getResolvedEnabledFixtures
|
||||
*/
|
||||
public function testIsConfigEnabledReturnsTheResolvedValue($enabled)
|
||||
{
|
||||
$pb = $this->getMockBuilder('Symfony\Component\DependencyInjection\ParameterBag\ParameterBag')
|
||||
->setMethods(array('resolveValue'))
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')
|
||||
->setMethods(array('getParameterBag'))
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$pb->expects($this->once())
|
||||
->method('resolveValue')
|
||||
->with($this->equalTo($enabled))
|
||||
->will($this->returnValue($enabled))
|
||||
;
|
||||
|
||||
$container->expects($this->once())
|
||||
->method('getParameterBag')
|
||||
->will($this->returnValue($pb))
|
||||
;
|
||||
|
||||
$extension = $this->getMockBuilder('Symfony\Component\DependencyInjection\Extension\Extension')
|
||||
->setMethods(array())
|
||||
->getMockForAbstractClass()
|
||||
;
|
||||
|
||||
$r = new \ReflectionMethod('Symfony\Component\DependencyInjection\Extension\Extension', 'isConfigEnabled');
|
||||
$r->setAccessible(true);
|
||||
|
||||
$r->invoke($extension, $container, array('enabled' => $enabled));
|
||||
}
|
||||
|
||||
public function getResolvedEnabledFixtures()
|
||||
{
|
||||
return array(
|
||||
array(true),
|
||||
array(false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage The config array has no 'enabled' key.
|
||||
*/
|
||||
public function testIsConfigEnabledOnNonEnableableConfig()
|
||||
{
|
||||
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$extension = $this->getMockBuilder('Symfony\Component\DependencyInjection\Extension\Extension')
|
||||
->setMethods(array())
|
||||
->getMockForAbstractClass()
|
||||
;
|
||||
|
||||
$r = new \ReflectionMethod('Symfony\Component\DependencyInjection\Extension\Extension', 'isConfigEnabled');
|
||||
$r->setAccessible(true);
|
||||
|
||||
$r->invoke($extension, $container, array());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user