[DIC] Better handling of enableable configurations #6852

Closed
wants to merge 12 commits into
from
+360 −145
View
20 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -91,10 +91,10 @@ private function addFormSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('form')
->info('form configuration')
- ->canBeDisabled()
+ ->canBeEnabled()
@stof
Symfony member
stof added a line comment Jan 23, 2013

This is not BC with 2.1. You need to add treatNullLike(array('enabled' => true))

@stof
Symfony member
stof added a line comment Jan 23, 2013

ah indeed, I forgot it

@vicb
vicb added a line comment Jan 23, 2013

I have tried to keep BC as much as possible (some other configs should probably get updated later) but it still needs a careful review !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
->end()
->arrayNode('csrf_protection')
- ->canBeDisabled()
+ ->canBeEnabled()
->children()
->scalarNode('field_name')->defaultValue('_token')->end()
->end()
@@ -109,7 +109,7 @@ private function addEsiSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('esi')
->info('esi configuration')
- ->canBeDisabled()
+ ->canBeEnabled()
->end()
->end()
;
@@ -121,7 +121,7 @@ private function addRouterProxySection(ArrayNodeDefinition $rootNode)
->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 @@ private function addProfilerSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('profiler')
->info('profiler configuration')
- ->canBeDisabled()
+ ->canBeEnabled()
->children()
->booleanNode('only_exceptions')->defaultFalse()->end()
->booleanNode('only_master_requests')->defaultFalse()->end()
@@ -176,8 +176,10 @@ private function addRouterSection(ArrayNodeDefinition $rootNode)
->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 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('translator')
->info('translator configuration')
- ->canBeDisabled()
+ ->canBeEnabled()
->children()
->scalarNode('fallback')->defaultValue('en')->end()
->end()
@@ -382,7 +384,7 @@ private function addValidationSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('validation')
->info('validation configuration')
- ->canBeDisabled()
+ ->canBeEnabled()
->children()
->scalarNode('cache')->end()
->booleanNode('enable_annotations')->defaultFalse()->end()
View
168 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -81,39 +81,25 @@ public function load(array $configs, ContainerBuilder $container)
$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['templating'])) {
@stof
Symfony member
stof added a line comment Jan 26, 2013

why keeping a isset here while you use an early return in other methods ?

@vicb
vicb added a line comment Jan 26, 2013

@stof For now this PR only fixes the current config and templating is not an enableable node as of today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
}
- if (isset($config['profiler'])) {
- $this->registerProfilerConfiguration($config['profiler'], $container, $loader);
- }
+ $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);
}
- if (isset($config['templating'])) {
- $this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
- }
-
- if (isset($config['translator'])) {
- $this->registerTranslatorConfiguration($config['translator'], $container);
- }
-
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
$this->addClassesToCompile(array(
@@ -161,7 +147,7 @@ public function load(array $configs, ContainerBuilder $container)
private function registerFormConfiguration($config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('form.xml');
- if (isset($config['csrf_protection'])) {
+ if ($this->isConfigEnabled($container, $config['csrf_protection'])) {
@Tobion
Symfony member
Tobion added a line comment Jan 23, 2013

In line 156 you can set $container->setParameter('form.type_extension.csrf.enabled', true); because it's only set when it avaluates to true anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
if (!isset($config['session'])) {
throw new \LogicException('CSRF protection needs that sessions are enabled.');
}
@@ -170,36 +156,44 @@ private function registerFormConfiguration($config, ContainerBuilder $container,
}
$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 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $
}
}
- if (!$config['enabled']) {
+ if (!$this->isConfigEnabled($container, $config)) {
$container->getDefinition('profiler')->addMethodCall('disable', array());
}
}
@@ -530,61 +524,63 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt
*/
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']));
-
- // 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\Form\Form')) {
- $r = new \ReflectionClass('Symfony\Component\Form\Form');
+ if (!$this->isConfigEnabled($container, $config)) {
+ return;
+ }
- $dirs[] = dirname($r->getFilename()).'/Resources/translations';
- }
- if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
- $r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException');
+ // 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';
- }
- $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;
- }
+ // 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\Form\Form')) {
+ $r = new \ReflectionClass('Symfony\Component\Form\Form');
+
+ $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 = $container->getParameter('kernel.root_dir').'/Resources/translations')) {
+ 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)
- ;
-
- 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));
- }
+ // 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));
}
}
}
@@ -598,6 +594,10 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
*/
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']);
View
97 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -16,46 +16,41 @@
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 @@ public function testInvalidTypeTrustedProxies()
{
$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 @@ public function testInvalidValueTrustedProxies()
{
$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%',
+ ),
+ );
}
}
View
2 .../Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_annotations.php
@@ -3,7 +3,7 @@
$container->loadFromExtension('framework', array(
'secret' => 's3cr3t',
'validation' => array(
- 'enabled' => true,
+ 'enabled' => true,
'enable_annotations' => true,
),
));
View
3 src/Symfony/Component/Config/CHANGELOG.md
@@ -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
View
19 src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php
@@ -214,16 +214,32 @@ public function canBeUnset($allow = true)
/**
* 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 @@ public function canBeEnabled()
public function canBeDisabled()
{
$this
+ ->addDefaultsIfNotSet()
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->treatNullLike(array('enabled' => true))
View
15 src/Symfony/Component/Config/Definition/Processor.php
@@ -79,18 +79,19 @@ public static function normalizeConfig($config, $key, $plural = null)
$plural = $key.'s';
}
- $values = array();
if (isset($config[$plural])) {
- $values = $config[$plural];
- } elseif (isset($config[$key])) {
+ return $config[$plural];
+ }
+
+ if (isset($config[$key])) {
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
// only one
- $values = array($config[$key]);
- } else {
- $values = $config[$key];
+ return array($config[$key]);
}
+
+ return $config[$key];
}
- return $values;
+ return array();
}
}
View
12 src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php
@@ -25,19 +25,13 @@ public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed()
}
/**
- * 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'));
}
/**
View
50 src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php
@@ -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 @@ public function providePrototypeNodeSpecificCalls()
public function testConcreteNodeSpecificOption()
{
$node = new ArrayNodeDefinition('root');
- $node->addDefaultsIfNotSet()->prototype('array');
+ $node
+ ->addDefaultsIfNotSet()
+ ->prototype('array')
+ ;
$node->getNode();
}
@@ -149,6 +153,50 @@ public function testNestedPrototypedArrayNodes()
$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);
View
1 src/Symfony/Component/DependencyInjection/CHANGELOG.md
@@ -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
View
37 src/Symfony/Component/DependencyInjection/Extension/Extension.php
@@ -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 @@ public function getNamespace()
*
* @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 @@ public function getConfiguration(array $config, ContainerBuilder $container)
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']);
+ }
}
View
81 src/Symfony/Component/DependencyInjection/Tests/Extension/ExtensionTest.php
@@ -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());
+ }
+}