[DIC] Better handling of enableable configurations

This commit is contained in:
Victor 2013-01-23 15:18:20 +01:00 committed by Fabien Potencier
parent 4bdfb92a35
commit fde7585967
12 changed files with 362 additions and 147 deletions

View File

@ -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()

View File

@ -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']);

View File

@ -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%',
),
);
}
}

View File

@ -3,7 +3,7 @@
$container->loadFromExtension('framework', array(
'secret' => 's3cr3t',
'validation' => array(
'enabled' => true,
'enabled' => true,
'enable_annotations' => true,
),
));

View File

@ -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 File

@ -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))

View File

@ -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();
}
}

View File

@ -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'));
}
/**

View File

@ -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);

View File

@ -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 File

@ -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']);
}
}

View File

@ -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());
}
}