Skip to content

Instantly share code, notes, and snippets.

@jmikola
Created January 28, 2011 20:35
Show Gist options
  • Select an option

  • Save jmikola/800893 to your computer and use it in GitHub Desktop.

Select an option

Save jmikola/800893 to your computer and use it in GitHub Desktop.
Adding intelligent configuration merging to FrameworkExtension
<?php
class FrameworkExtension extends Extension
{
public function configLoad(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
$loader->load('web.xml');
$loader->load('form.xml');
$loader->load('services.xml');
if ($container->getParameter('kernel.debug')) {
$loader->load('debug.xml');
$container->setDefinition('event_dispatcher', $container->findDefinition('debug.event_dispatcher'));
$container->setAlias('debug.event_dispatcher', 'event_dispatcher');
}
$this->doConfigLoad($this->configMerge($configs), $container);
$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\ParameterBag',
'Symfony\\Component\\HttpFoundation\\HeaderBag',
'Symfony\\Component\\HttpFoundation\\Request',
'Symfony\\Component\\HttpFoundation\\Response',
'Symfony\\Component\\HttpFoundation\\ResponseHeaderBag',
'Symfony\\Component\\HttpKernel\\HttpKernel',
'Symfony\\Component\\HttpKernel\\ResponseListener',
'Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver',
'Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface',
'Symfony\\Bundle\\FrameworkBundle\\RequestListener',
'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerNameParser',
'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver',
'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller',
'Symfony\\Component\\EventDispatcher\\EventInterface',
'Symfony\\Component\\EventDispatcher\\Event',
'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface',
'Symfony\\Component\\EventDispatcher\\EventDispatcher',
'Symfony\\Bundle\\FrameworkBundle\\EventDispatcher',
'Symfony\\Component\\Form\\FormContext',
'Symfony\\Component\\Form\\FormContextInterface',
));
}
/**
* Merges a set of configurations into one, normalized array.
*
* @param array $configs An array of option arrays to merge
* @return array
*/
protected function configMerge(array $configs)
{
// The default and available options. These are very specific to this method.
$options = array(
'cache_warmer' => null,
'charset' => null,
'csrf_protection' => array(
'enabled' => null,
'field_name' => null,
'secret' => null,
),
'document_root' => null,
'error_handler' => null,
'esi' => array(
'enabled' => null,
),
'i18n' => null,
'ide' => null,
'param_converter' => null,
'profiler' => array(
'only_exceptions' => null,
'matcher' => array(
'ip' => null,
'path' => null,
'service' => null,
),
),
'router' => array(
'cache_warmer' => null,
'resource' => null,
),
'session' => array(
'auto_start' => null,
'class' => null,
'default_locale' => null,
'storage_id' => 'native',
// Storage driver options
'name' => null,
'lifetime' => null,
'path' => null,
'domain' => null,
'secure' => null,
'httponly' => null,
'pdo.db_table' => null,
'pdo.db_id_col' => null,
'pdo.db_data_col' => null,
'pdo.db_time_col' => null,
),
'templating' => array(
'assets_version' => null,
'assets_base_urls' => null,
'cache' => null,
'cache_warmer' => null,
'engines' => array(),
'loaders' => array(),
),
'test' => null,
'translator' => array(
'enabled' => null,
'fallback' => null,
),
'validation' => array(
'enabled' => null,
'annotations' => array(
'enabled' => null,
'namespaces' => array(),
),
),
);
foreach ($configs as $config) {
$config = $this->normalizeKeys($config);
if (isset($config['templating']) && is_array($config['templating'])) {
$config['templating']['engines'] = $this->normalizeConfig($config['templating'], 'engine');
$config['templating']['loaders'] = $this->normalizeConfig($config['templating'], 'loader');
unset($config['templating']['engine'], $config['templating']['loader']);
}
if (isset($config['validation']['annotations']) && is_array($config['validation']['annotations'])) {
$config['validation']['annotations']['namespaces'] = $this->normalizeConfig($config['validation']['annotations'], 'namespace');
unset($config['validation']['annotations']['namespace']);
}
$options = $this->mergeOptions($options, $config);
}
return $options;
}
/**
* Merges a single option level.
*
* @param array $options The array that will be modified and returned
* @param array $config The array to be merged in
* @param string $path The base path for this option level
* @throw InvalidArgumentException When an unsupported option is found
*/
protected function mergeOptions(array $options, array $config, $path = null)
{
if ($unsupportedOptions = array_diff_key($config, $options)) {
throw new \InvalidArgumentException('The following options are not supported: '.implode(', ', $unsupportedOptions));
}
foreach ($options as $key => $value) {
if (array_key_exists($key, $config)) {
$optionPath = $path ? $path . '.' . $key : $key;
if (is_array($value) && !is_array($config[$key])) {
throw new \InvalidArgumentException(sprintf('Expected array type for option "%s", %s given', $optionPath, gettype($config[$key])));
}
switch ($optionPath) {
case 'templating.engines':
case 'templating.loaders':
$options[$key] = array_unique(array_merge($value, $config[$key]));
break;
case 'validation.annotations.namespaces':
$options[$key] = array_merge($value, $config[$key]);
break;
default:
if (is_array($value)) {
$options[$key] = $this->mergeOptions($value, $config[$key], $optionPath);
} else {
$options[$key] = $config[$key];
}
}
}
}
return $options;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment