diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 5151325450022..6cad90e26cdc2 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -24,7 +24,8 @@
./src/Symfony/Bundle/*/Resources
./src/Symfony/Component/*/Resources
- ./src/Symfony/Component/HttpKernel/bootstrap*
+ ./src/Symfony/Component/HttpKernel/bootstrap.php
+ ./src/Symfony/Component/HttpKernel/bootstrap_cache.php
diff --git a/src/Symfony/Bundle/CompatAssetsBundle/CompatAssetsBundle.php b/src/Symfony/Bundle/CompatAssetsBundle/CompatAssetsBundle.php
index fbdb2663aa5fb..9e1158984b4f7 100644
--- a/src/Symfony/Bundle/CompatAssetsBundle/CompatAssetsBundle.php
+++ b/src/Symfony/Bundle/CompatAssetsBundle/CompatAssetsBundle.php
@@ -20,19 +20,4 @@
*/
class CompatAssetsBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php b/src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php
index 813c6033727a7..55fc875889407 100755
--- a/src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php
+++ b/src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php
@@ -408,6 +408,7 @@ protected function loadOrmEntityManager(array $entityManager, ContainerBuilder $
new Reference(sprintf('doctrine.orm.%s_configuration', $entityManager['name']))
);
$ormEmDef = new Definition('%doctrine.orm.entity_manager_class%', $ormEmArgs);
+ $ormEmDef->setFactoryClass('%doctrine.orm.entity_manager_class%');
$ormEmDef->setFactoryMethod('create');
$ormEmDef->addTag('doctrine.orm.entity_manager');
$container->setDefinition($entityManagerService, $ormEmDef);
diff --git a/src/Symfony/Bundle/DoctrineBundle/DoctrineBundle.php b/src/Symfony/Bundle/DoctrineBundle/DoctrineBundle.php
index 5e4e6ab21507e..de1d170543fde 100644
--- a/src/Symfony/Bundle/DoctrineBundle/DoctrineBundle.php
+++ b/src/Symfony/Bundle/DoctrineBundle/DoctrineBundle.php
@@ -31,20 +31,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new RegisterEventListenersAndSubscribersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
index bd9fbefc9eaff..46a4e4046771b 100755
--- a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
@@ -157,6 +157,7 @@ public function testDependencyInjectionConfigurationDefaults()
$definition = $container->getDefinition('doctrine.orm.default_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
@@ -198,6 +199,7 @@ public function testSingleEntityManagerConfiguration()
$definition = $container->getDefinition('doctrine.orm.default_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
@@ -239,6 +241,7 @@ public function testLoadSimpleSingleConnection()
$definition = $container->getDefinition('doctrine.orm.default_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
@@ -279,6 +282,7 @@ public function testLoadSingleConnection()
$definition = $container->getDefinition('doctrine.orm.default_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
@@ -313,6 +317,7 @@ public function testLoadMultipleConnections()
$definition = $container->getDefinition('doctrine.orm.dm1_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
@@ -334,6 +339,7 @@ public function testLoadMultipleConnections()
$definition = $container->getDefinition('doctrine.orm.dm2_entity_manager');
$this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.orm.entity_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.orm.entity_manager', $definition->getTags());
diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
index 3cd2803b1f05a..899d3e178eb0f 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
@@ -6,19 +6,4 @@
class AnnotationsBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
-}
\ No newline at end of file
+}
diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/Vendor/AnnotationsBundle/AnnotationsBundle.php b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/Vendor/AnnotationsBundle/AnnotationsBundle.php
index 3e08c3a86e8b8..641edc122e105 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/Vendor/AnnotationsBundle/AnnotationsBundle.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/Vendor/AnnotationsBundle/AnnotationsBundle.php
@@ -6,19 +6,4 @@
class AnnotationsBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
-}
\ No newline at end of file
+}
diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
index 9980c7bef12ea..3bdd9873eaa29 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
@@ -6,19 +6,4 @@
class XmlBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
index 225ce0f90368f..c89784c34c4ac 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
@@ -6,19 +6,4 @@
class YamlBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineMigrationsBundle/DoctrineMigrationsBundle.php b/src/Symfony/Bundle/DoctrineMigrationsBundle/DoctrineMigrationsBundle.php
index d987d30d79cda..6fadd42c11c35 100644
--- a/src/Symfony/Bundle/DoctrineMigrationsBundle/DoctrineMigrationsBundle.php
+++ b/src/Symfony/Bundle/DoctrineMigrationsBundle/DoctrineMigrationsBundle.php
@@ -21,19 +21,4 @@
*/
class DoctrineMigrationsBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php
index 880005e174879..0eb11749b3f48 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php
@@ -165,6 +165,7 @@ protected function loadDocumentManager(array $documentManager, ContainerBuilder
new Reference($eventManagerId),
);
$odmDmDef = new Definition('%doctrine.odm.mongodb.document_manager_class%', $odmDmArgs);
+ $odmDmDef->setFactoryClass('%doctrine.odm.mongodb.document_manager_class%');
$odmDmDef->setFactoryMethod('create');
$odmDmDef->addTag('doctrine.odm.mongodb.document_manager');
$container->setDefinition(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']), $odmDmDef);
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/DoctrineMongoDBBundle.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/DoctrineMongoDBBundle.php
index d6d409c473b95..99e205e977a5f 100755
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/DoctrineMongoDBBundle.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/DoctrineMongoDBBundle.php
@@ -35,20 +35,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new CreateProxyDirectoryPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new CreateHydratorDirectoryPass(), PassConfig::TYPE_BEFORE_REMOVING);
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/AbstractMongoDBExtensionTest.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/AbstractMongoDBExtensionTest.php
index b500b08e06350..dee13dabc7669 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/AbstractMongoDBExtensionTest.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/AbstractMongoDBExtensionTest.php
@@ -65,6 +65,7 @@ public function testDependencyInjectionConfigurationDefaults()
$definition = $container->getDefinition('doctrine.odm.mongodb.default_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
@@ -92,6 +93,7 @@ public function testSingleDocumentManagerConfiguration()
$definition = $container->getDefinition('doctrine.odm.mongodb.default_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
@@ -126,6 +128,7 @@ public function testLoadSimpleSingleConnection()
$definition = $container->getDefinition('doctrine.odm.mongodb.default_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
@@ -154,6 +157,7 @@ public function testLoadSingleConnection()
$definition = $container->getDefinition('doctrine.odm.mongodb.default_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
@@ -184,6 +188,7 @@ public function testLoadMultipleConnections()
$definition = $container->getDefinition('doctrine.odm.mongodb.dm1_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
@@ -199,6 +204,7 @@ public function testLoadMultipleConnections()
$definition = $container->getDefinition('doctrine.odm.mongodb.dm2_document_manager');
$this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getClass());
+ $this->assertEquals('%doctrine.odm.mongodb.document_manager_class%', $definition->getFactoryClass());
$this->assertEquals('create', $definition->getFactoryMethod());
$this->assertArrayHasKey('doctrine.odm.mongodb.document_manager', $definition->getTags());
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
index 2c4eee1523a52..23b96a825d60f 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/AnnotationsBundle/AnnotationsBundle.php
@@ -6,19 +6,4 @@
class AnnotationsBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
index bdb28af65133b..f02676fcb8d6d 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/XmlBundle/XmlBundle.php
@@ -6,19 +6,4 @@
class XmlBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
index 8c06610c5eb1e..3c63ccb389c15 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/DependencyInjection/Fixtures/Bundles/YamlBundle/YamlBundle.php
@@ -6,19 +6,4 @@
class YamlBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplatePathsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplatePathsCacheWarmer.php
index 3477454468d35..032b927804292 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplatePathsCacheWarmer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplatePathsCacheWarmer.php
@@ -64,7 +64,7 @@ protected function computeTemplatePaths()
$prefix = '/Resources/views';
$templates = array();
foreach ($this->kernel->getBundles() as $name => $bundle) {
- if (!is_dir($dir = $bundle->getNormalizedPath().$prefix)) {
+ if (!is_dir($dir = $bundle->getPath().$prefix)) {
continue;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
new file mode 100644
index 0000000000000..418a7544144cc
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -0,0 +1,220 @@
+
+ */
+class Configuration
+{
+ /**
+ * Generates the configuration tree.
+ *
+ * @param boolean $kernelDebug The kernel.debug DIC parameter
+ * @return \Symfony\Component\DependencyInjection\Configuration\NodeInterface
+ */
+ public function getConfigTree($kernelDebug)
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('app:config', 'array');
+
+ $rootNode
+ ->scalarNode('cache_warmer')->defaultValue(!$kernelDebug)->end()
+ ->scalarNode('charset')->end()
+ ->scalarNode('document_root')->end()
+ ->scalarNode('error_handler')->end()
+ ->scalarNode('ide')->end()
+ ->booleanNode('test')->end()
+ ;
+
+ $this->addCsrfProtectionSection($rootNode);
+ $this->addEsiSection($rootNode);
+ $this->addProfilerSection($rootNode);
+ $this->addRouterSection($rootNode);
+ $this->addSessionSection($rootNode);
+ $this->addTemplatingSection($rootNode);
+ $this->addTranslatorSection($rootNode);
+ $this->addValidationSection($rootNode);
+
+ return $treeBuilder->buildTree();
+ }
+
+ private function addCsrfProtectionSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('csrf_protection')
+ ->canBeUnset()
+ ->treatNullLike(array('enabled' => true))
+ ->treatTrueLike(array('enabled' => true))
+ ->booleanNode('enabled')->end()
+ ->scalarNode('field_name')->end()
+ ->scalarNode('secret')->end()
+ ->end()
+ ;
+ }
+
+ private function addEsiSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('esi')
+ ->canBeUnset()
+ ->treatNullLike(array('enabled' => true))
+ ->treatTrueLike(array('enabled' => true))
+ ->booleanNode('enabled')->end()
+ ->end()
+ ;
+ }
+
+ private function addProfilerSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('profiler')
+ ->canBeUnset()
+ ->treatNullLike(array())
+ ->treatTrueLike(array())
+ ->booleanNode('only_exceptions')->end()
+ ->arrayNode('matcher')
+ ->canBeUnset()
+ ->scalarNode('ip')->end()
+ ->scalarNode('path')->end()
+ ->scalarNode('service')->end()
+ ->end()
+ ->end()
+ ;
+ }
+
+ private function addRouterSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('router')
+ ->canBeUnset()
+ ->scalarNode('cache_warmer')->end()
+ ->scalarNode('resource')->isRequired()->end()
+ ->end()
+ ;
+ }
+
+ private function addSessionSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('session')
+ ->canBeUnset()
+ ->treatNullLike(array())
+ ->treatTrueLike(array())
+ // Strip "pdo." prefix from option keys, since dots cannot appear in node names
+ ->beforeNormalization()
+ ->ifArray()
+ ->then(function($v){
+ foreach ($v as $key => $value) {
+ if (0 === strncmp('pdo.', $key, 4)) {
+ $v[substr($key, 4)] = $value;
+ unset($v[$key]);
+ }
+ }
+ return $v;
+ })
+ ->end()
+ ->booleanNode('auto_start')->end()
+ ->scalarNode('class')->end()
+ ->scalarNode('default_locale')->end()
+ ->scalarNode('storage_id')->defaultValue('native')->end()
+ // NativeSessionStorage options
+ ->scalarNode('name')->end()
+ ->scalarNode('lifetime')->end()
+ ->scalarNode('path')->end()
+ ->scalarNode('domain')->end()
+ ->booleanNode('secure')->end()
+ ->booleanNode('httponly')->end()
+ // PdoSessionStorage options
+ ->scalarNode('db_table')->end()
+ ->scalarNode('db_id_col')->end()
+ ->scalarNode('db_data_col')->end()
+ ->scalarNode('db_time_col')->end()
+ ->end()
+ ;
+ }
+
+ private function addTemplatingSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('templating')
+ ->canBeUnset()
+ ->scalarNode('assets_version')->end()
+ ->scalarNode('assets_base_urls')->end()
+ ->scalarNode('cache')->end()
+ ->scalarNode('cache_warmer')->end()
+ ->fixXmlConfig('engine')
+ ->arrayNode('engines')
+ ->requiresAtLeastOneElement()
+ ->beforeNormalization()
+ ->ifTrue(function($v){ return !is_array($v); })
+ ->then(function($v){ return array($v); })
+ ->end()
+ ->prototype('scalar')
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && isset($v['id']); })
+ ->then(function($v){ return $v['id']; })
+ ->end()
+ ->end()
+ ->end()
+ ->fixXmlConfig('loader')
+ ->arrayNode('loaders')
+ ->beforeNormalization()
+ ->ifTrue(function($v){ return !is_array($v); })
+ ->then(function($v){ return array($v); })
+ ->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ;
+ }
+
+ private function addTranslatorSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('translator')
+ ->canBeUnset()
+ ->booleanNode('enabled')->defaultTrue()->end()
+ ->scalarNode('fallback')->end()
+ ->end()
+ ;
+ }
+
+ private function addValidationSection(NodeBuilder $rootNode)
+ {
+ $rootNode
+ ->arrayNode('validation')
+ ->canBeUnset()
+ // For XML, namespace is a child of validation, so it must be moved under annotations
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && !empty($v['annotations']) && !empty($v['namespace']); })
+ ->then(function($v){
+ $v['annotations'] = array('namespace' => $v['namespace']);
+ return $v;
+ })
+ ->end()
+ ->booleanNode('enabled')->end()
+ ->arrayNode('annotations')
+ ->canBeUnset()
+ ->treatNullLike(array())
+ ->treatTrueLike(array())
+ ->fixXmlConfig('namespace')
+ ->arrayNode('namespaces')
+ ->containsNameValuePairsWithKeyAttribute('prefix')
+ ->prototype('scalar')
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && isset($v['namespace']); })
+ ->then(function($v){ return $v['namespace']; })
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index ecbeae5bb72d7..411835221d3dc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -11,151 +11,119 @@
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
-use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
-use Symfony\Component\DependencyInjection\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Configuration\Processor;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+use Symfony\Component\DependencyInjection\Resource\FileResource;
use Symfony\Component\Finder\Finder;
-use Symfony\Component\HttpFoundation\RequestMatcher;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\Form\FormContext;
/**
* FrameworkExtension.
*
* @author Fabien Potencier
+ * @author Jeremy Mikola
*/
class FrameworkExtension extends Extension
{
- public function configLoad(array $configs, ContainerBuilder $container)
- {
- foreach ($configs as $config) {
- $this->doConfigLoad($config, $container);
- }
- }
-
/**
- * Loads the web configuration.
+ * Responds to the app.config configuration parameter.
*
- * @param array $config An array of configuration settings
- * @param ContainerBuilder $container A ContainerBuilder instance
+ * @param array $configs
+ * @param ContainerBuilder $container
*/
- protected function doConfigLoad(array $config, ContainerBuilder $container)
+ public function configLoad(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- if (!$container->hasDefinition('controller_resolver')) {
- $loader->load('web.xml');
- }
+ $loader->load('web.xml');
+ $loader->load('form.xml');
+ $loader->load('services.xml');
- if (!$container->hasDefinition('form.factory')) {
- $loader->load('form.xml');
- }
+ // A translator must always be registered (as support is included by
+ // default in the Form component). If disabled, an identity translator
+ // will be used and everything will still work as expected.
+ $loader->load('translation.xml');
- if (isset($config['csrf-protection'])) {
- $config['csrf_protection'] = $config['csrf-protection'];
+ 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');
}
- if (isset($config['csrf_protection'])) {
- foreach (array('enabled', 'field_name', 'field-name', 'secret') as $key) {
- if (isset($config['csrf_protection'][$key])) {
- $container->setParameter('form.csrf_protection.'.strtr($key, '-', '_'),
- $config['csrf_protection'][$key]);
- }
- }
- }
+ $processor = new Processor();
+ $configuration = new Configuration();
- if (isset($config['ide'])) {
- switch ($config['ide']) {
- case 'textmate':
- $pattern = 'txmt://open?url=file://%%f&line=%%l';
- break;
-
- case 'macvim':
- $pattern = 'mvim://open?url=file://%%f&line=%%l';
- break;
-
- default:
- // should be the link pattern then
- $pattern = $config['ide'];
- }
+ $config = $processor->process($configuration->getConfigTree($container->getParameter('kernel.debug')), $configs);
- $container->setParameter('debug.file_link_format', $pattern);
- }
+ $container->setParameter('kernel.cache_warmup', $config['cache_warmer']);
- foreach (array('document_root', 'document-root') as $key) {
- if (isset($config[$key])) {
- $container->setParameter('document_root', $config[$key]);
- }
+ if (isset($config['charset'])) {
+ $container->setParameter('kernel.charset', $config['charset']);
}
- if (!$container->hasDefinition('event_dispatcher')) {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('services.xml');
+ if (isset($config['document_root'])) {
+ $container->setParameter('document_root', $config['document_root']);
+ }
- 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');
+ if (isset($config['error_handler'])) {
+ if (false === $config['error_handler']) {
+ $container->getDefinition('error_handler')->setMethodCalls(array());
+ } else {
+ $container->getDefinition('error_handler')->addMethodCall('register', array());
+ $container->setParameter('error_handler.level', $config['error_handler']);
}
}
- if (isset($config['charset'])) {
- $container->setParameter('kernel.charset', $config['charset']);
+ if (isset($config['ide'])) {
+ $patterns = array(
+ 'textmate' => 'txmt://open?url=file://%%f&line=%%l',
+ 'macvim' => 'mvim://open?url=file://%%f&line=%%l',
+ );
+ $pattern = isset($patterns[$config['ide']]) ? $patterns[$config['ide']] : $config['ide'];
+ $container->setParameter('debug.file_link_format', $pattern);
}
- foreach (array('error_handler', 'error-handler') as $key) {
- if (array_key_exists($key, $config)) {
- if (false === $config[$key]) {
- $container->getDefinition('error_handler')->setMethodCalls(array());
- } else {
- $container->getDefinition('error_handler')->addMethodCall('register', array());
- $container->setParameter('error_handler.level', $config[$key]);
- }
- }
+ if (isset($config['test']) && $config['test']) {
+ $loader->load('test.xml');
+ $config['session']['storage_id'] = 'array';
}
- if (isset($config['router'])) {
- $this->registerRouterConfiguration($config, $container);
+ if (isset($config['csrf_protection'])) {
+ $this->registerCsrfProtectionConfiguration($config['csrf_protection'], $container);
}
- if (isset($config['profiler'])) {
- $this->registerProfilerConfiguration($config, $container);
+ if (isset($config['esi'])) {
+ $this->registerEsiConfiguration($config['esi'], $loader);
}
- if (isset($config['validation']['enabled'])) {
- $this->registerValidationConfiguration($config, $container);
+ if (isset($config['profiler'])) {
+ $this->registerProfilerConfiguration($config['profiler'], $container, $loader);
}
- if (array_key_exists('templating', $config)) {
- $this->registerTemplatingConfiguration($config, $container);
+ if (isset($config['router'])) {
+ $this->registerRouterConfiguration($config['router'], $container, $loader);
}
- if (array_key_exists('test', $config)) {
- $this->registerTestConfiguration($config, $container);
+ if (isset($config['session'])) {
+ $this->registerSessionConfiguration($config['session'], $container, $loader);
}
- if (array_key_exists('session', $config)) {
- $this->registerSessionConfiguration($config, $container);
+ if (isset($config['templating'])) {
+ $this->registerTemplatingConfiguration($config['templating'], $container, $loader);
}
- // translator must always be registered (as support is included by default for forms for instance)
- // if you disable it, an identity translator will be used and everything will still work as expected
- $this->registerTranslatorConfiguration($config, $container);
-
- if (array_key_exists('esi', $config)) {
- $this->registerEsiConfiguration($config, $container);
+ if (isset($config['translator'])) {
+ $this->registerTranslatorConfiguration($config['translator'], $container);
}
- if (isset($config['cache-warmer'])) {
- $config['cache_warmer'] = $config['cache-warmer'];
+ if (isset($config['validation'])) {
+ $this->registerValidationConfiguration($config['validation'], $container, $loader);
}
- $warmer = isset($config['cache_warmer']) ? $config['cache_warmer'] : !$container->getParameter('kernel.debug');
- $container->setParameter('kernel.cache_warmup', $warmer);
-
$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\ParameterBag',
'Symfony\\Component\\HttpFoundation\\HeaderBag',
@@ -178,235 +146,114 @@ protected function doConfigLoad(array $config, ContainerBuilder $container)
'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface',
'Symfony\\Component\\EventDispatcher\\EventDispatcher',
'Symfony\\Bundle\\FrameworkBundle\\EventDispatcher',
-
- 'Symfony\\Component\\Form\\FormContext',
- 'Symfony\\Component\\Form\\FormContextInterface',
));
}
/**
- * Loads the templating configuration.
+ * Loads the CSRF protection configuration.
*
- * @param array $config An array of configuration settings
+ * @param array $config A CSRF protection configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
*/
- protected function registerTemplatingConfiguration(array $config, ContainerBuilder $container)
+ private function registerCsrfProtectionConfiguration(array $config, ContainerBuilder $container)
{
- $config = isset($config['templating']) ? $config['templating'] : array();
-
- if (!$container->hasDefinition('templating.locator')) {
- $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- $loader->load('templating.xml');
- $loader->load('templating_php.xml');
-
- if ($container->getParameter('kernel.debug')) {
- $loader->load('templating_debug.xml');
- }
- }
-
- if (array_key_exists('assets-version', $config)) {
- $container->setParameter('templating.assets.version', $config['assets-version']);
- }
-
- if (array_key_exists('assets_version', $config)) {
- $container->setParameter('templating.assets.version', $config['assets_version']);
- }
-
- if (array_key_exists('assets-base-urls', $config)) {
- $container->setParameter('templating.assets.base_urls', $config['assets-base-urls']);
- }
-
- if (array_key_exists('assets_base_urls', $config)) {
- $container->setParameter('templating.assets.base_urls', $config['assets_base_urls']);
- }
-
- // loaders
- if (isset($config['loader'])) {
- $loaders = array();
- $ids = is_array($config['loader']) ? $config['loader'] : array($config['loader']);
- foreach ($ids as $id) {
- $loaders[] = new Reference($id);
- }
-
- if (1 === count($loaders)) {
- $container->setAlias('templating.loader', (string) $loaders[0]);
- } else {
- $container->getDefinition('templating.loader.chain')->addArgument($loaders);
- $container->setAlias('templating.loader', 'templating.loader.chain');
- }
- }
-
- // cache?
- $container->setParameter('templating.loader.cache.path', null);
- if (isset($config['cache'])) {
- // wrap the loader with some cache
- $container->setDefinition('templating.loader.wrapped', $container->findDefinition('templating.loader'));
- $container->setDefinition('templating.loader', $container->getDefinition('templating.loader.cache'));
- $container->setParameter('templating.loader.cache.path', $config['cache']);
- }
-
- if (isset($config['cache-warmer'])) {
- $config['cache_warmer'] = $config['cache-warmer'];
- }
-
- if (isset($config['cache_warmer']) && $config['cache_warmer']) {
- $container->getDefinition('templating.cache_warmer.template_paths')->addTag('kernel.cache_warmer');
- $container->setAlias('templating.locator', 'templating.locator.cached');
- }
-
- // engines
- if (!$engines = $this->normalizeConfig($config, 'engine')) {
- throw new \LogicException('You must register at least one templating engine.');
- }
-
- $this->addClassesToCompile(array(
- 'Symfony\\Bundle\\FrameworkBundle\\Templating\\EngineInterface',
- 'Symfony\\Component\\Templating\\EngineInterface',
- 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\TemplateLocatorInterface',
- $container->findDefinition('templating.locator')->getClass(),
- ));
-
- foreach ($engines as $i => $engine) {
- $id = is_array($engine) ? $engine['id'] : $engine;
- $engines[$i] = new Reference('templating.engine.'.$id);
-
- if ('php' === $id) {
- $this->addClassesToCompile(array(
- 'Symfony\\Component\\Templating\\PhpEngine',
- 'Symfony\\Component\\Templating\\TemplateNameParserInterface',
- 'Symfony\\Component\\Templating\\TemplateNameParser',
- 'Symfony\\Component\\Templating\\Loader\\LoaderInterface',
- 'Symfony\\Component\\Templating\\Storage\\Storage',
- 'Symfony\\Component\\Templating\\Storage\\FileStorage',
- 'Symfony\\Bundle\\FrameworkBundle\\Templating\\PhpEngine',
- 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateNameParser',
- 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\FilesystemLoader',
- ));
+ foreach (array('enabled', 'field_name', 'secret') as $key) {
+ if (isset($config[$key])) {
+ $container->setParameter('form.csrf_protection.'.$key, $config[$key]);
}
}
-
- if (1 === count($engines)) {
- $container->setAlias('templating', (string) $engines[0]);
- } else {
- $def = $container->getDefinition('templating.engine.delegating');
- $def->setArgument(1, $engines);
-
- $container->setAlias('templating', 'templating.engine.delegating');
- }
- }
-
- /**
- * Loads the test configuration.
- *
- * @param array $config A configuration array
- * @param ContainerBuilder $container A ContainerBuilder instance
- */
- protected function registerTestConfiguration(array $config, ContainerBuilder $container)
- {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('test.xml');
-
- $container->setAlias('session.storage', 'session.storage.array');
}
/**
* Loads the ESI configuration.
*
- * @param array $config A configuration array
- * @param ContainerBuilder $container A ContainerBuilder instance
+ * @param array $config An ESI configuration array
+ * @param XmlFileLoader $loader An XmlFileLoader instance
*/
- protected function registerEsiConfiguration(array $config, ContainerBuilder $container)
+ private function registerEsiConfiguration(array $config, XmlFileLoader $loader)
{
- if (isset($config['esi']['enabled']) && $config['esi']['enabled']) {
- if (!$container->hasDefinition('esi')) {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('esi.xml');
- }
+ if (isset($config['enabled']) && $config['enabled']) {
+ $loader->load('esi.xml');
}
}
/**
- * Loads the translator configuration.
+ * Loads the profiler configuration.
*
- * @param array $config A configuration array
+ * @param array $config A profiler configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
+ * @param XmlFileLoader $loader An XmlFileLoader instance
*/
- protected function registerTranslatorConfiguration(array $config, ContainerBuilder $container)
+ private function registerProfilerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
- $first = false;
- if (!$container->hasDefinition('translator')) {
- $first = true;
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('translation.xml');
- }
+ $loader->load('profiling.xml');
+ $loader->load('collectors.xml');
- $config = array_key_exists('translator', $config) ? $config['translator'] : array();
- if (!is_array($config)) {
- $config = array();
+ if (isset($config['only_exceptions'])) {
+ $container->setParameter('profiler_listener.only_exceptions', $config['only_exceptions']);
}
- if (!isset($config['translator']['enabled']) || $config['translator']['enabled']) {
- // use the "real" translator
- $container->setDefinition('translator', $container->findDefinition('translator.real'));
+ if (isset($config['matcher'])) {
+ if (isset($config['matcher']['service'])) {
+ $container->setAlias('profiler.request_matcher', $config['matcher']['service']);
+ } elseif (isset($config['matcher']['ip']) || isset($config['matcher']['path'])) {
+ $definition = $container->register('profiler.request_matcher', 'Symfony\\Component\\HttpFoundation\\RequestMatcher');
+ $definition->setPublic(false);
- if ($first) {
- // translation directories
- $dirs = array();
- foreach ($container->getParameter('kernel.bundles') as $bundle) {
- $reflection = new \ReflectionClass($bundle);
- if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) {
- $dirs[] = $dir;
- }
- }
- if (is_dir($dir = $container->getParameter('kernel.root_dir').'/translations')) {
- $dirs[] = $dir;
+ if (isset($config['matcher']['ip'])) {
+ $definition->addMethodCall('matchIp', array($config['matcher']['ip']));
}
- // translation resources
- $resources = array();
- if ($dirs) {
- $finder = new Finder();
- $finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs);
- foreach ($finder as $file) {
- // filename is domain.locale.format
- list($domain, $locale, $format) = explode('.', $file->getBasename());
-
- $resources[] = array($format, (string) $file, $locale, $domain);
- }
+ if (isset($config['matcher']['path'])) {
+ $definition->addMethodCall('matchPath', array($config['matcher']['path']));
}
- $container->setParameter('translation.resources', $resources);
}
}
-
- if (array_key_exists('fallback', $config)) {
- $container->setParameter('translator.fallback_locale', $config['fallback']);
- }
}
/**
- * Loads the session configuration.
+ * Loads the router configuration.
*
- * @param array $config A configuration array
+ * @param array $config A router configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
+ * @param XmlFileLoader $loader An XmlFileLoader instance
+ * @throws \InvalidArgumentException if resource option is not set
*/
- protected function registerSessionConfiguration(array $config, ContainerBuilder $container)
+ private function registerRouterConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
- if (!$container->hasDefinition('session')) {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('session.xml');
+ $loader->load('routing.xml');
+
+ if (!isset($config['resource'])) {
+ throw new \InvalidArgumentException('Router configuration requires a resource option.');
}
- $config = isset($config['session']) ? $config['session'] : array();
+ $container->setParameter('routing.resource', $config['resource']);
- foreach (array('default_locale', 'default-locale') as $key) {
- if (isset($config[$key])) {
- $container->setParameter('session.default_locale', $config[$key]);
- }
+ if (isset($config['cache_warmer']) && $config['cache_warmer']) {
+ $container->getDefinition('router.cache_warmer')->addTag('kernel.cache_warmer');
+ $container->setAlias('router', 'router.cached');
}
- if (isset($config['auto-start'])) {
- $config['auto_start'] = $config['auto-start'];
- }
+ $this->addClassesToCompile(array(
+ 'Symfony\\Component\\Routing\\RouterInterface',
+ 'Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface',
+ 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
+ 'Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface',
+ 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
+ $container->findDefinition('router')->getClass(),
+ ));
+ }
+
+ /**
+ * Loads the session configuration.
+ *
+ * @param array $config A session configuration array
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ * @param XmlFileLoader $loader An XmlFileLoader instance
+ */
+ private function registerSessionConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
+ {
+ $loader->load('session.xml');
if (isset($config['auto_start']) && $config['auto_start']) {
$container->getDefinition('session')->addMethodCall('start');
@@ -416,29 +263,19 @@ protected function registerSessionConfiguration(array $config, ContainerBuilder
$container->setParameter('session.class', $config['class']);
}
- if (isset($config['storage-id'])) {
- $config['storage_id'] = $config['storage-id'];
+ if (isset($config['default_locale'])) {
+ $container->setParameter('session.default_locale', $config['default_locale']);
}
- if (isset($config['storage_id'])) {
- $container->setAlias('session.storage', 'session.storage.'.$config['storage_id']);
- } else {
- $config['storage_id'] = 'native';
- }
-
- $options = $container->getParameter('session.storage.'.strtolower($config['storage_id']).'.options');
- foreach (array('name', 'lifetime', 'path', 'domain', 'secure', 'httponly', 'cache_limiter', 'pdo.db_table', 'pdo.db_id_col', 'pdo.db_data_col', 'pdo.db_time_col') as $name) {
- $key = str_replace('pdo.', '', $name);
- if (isset($config[$name])) {
- $options[$key] = $config[$name];
- }
+ $container->setAlias('session.storage', 'session.storage.'.$config['storage_id']);
- $nName = str_replace('_', '-', $name);
- if (isset($config[$nName])) {
- $options[$key] = $config[$nName];
+ $options = $container->getParameter('session.storage.'.$config['storage_id'].'.options');
+ foreach (array('name', 'lifetime', 'path', 'domain', 'secure', 'httponly', 'db_table', 'db_id_col', 'db_data_col', 'db_time_col') as $key) {
+ if (isset($config[$key])) {
+ $options[$key] = $config[$key];
}
}
- $container->setParameter('session.storage.'.strtolower($config['storage_id']).'.options', $options);
+ $container->setParameter('session.storage.'.$config['storage_id'].'.options', $options);
$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\Session',
@@ -448,167 +285,204 @@ protected function registerSessionConfiguration(array $config, ContainerBuilder
}
/**
- * Loads the router configuration.
+ * Loads the templating configuration.
*
- * @param array $config A configuration array
+ * @param array $config A templating configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
+ * @param XmlFileLoader $loader An XmlFileLoader instance
+ * @throws \LogicException if no engines are defined
*/
- protected function registerRouterConfiguration(array $config, ContainerBuilder $container)
+ private function registerTemplatingConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
- if (!$container->hasDefinition('router')) {
- $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- $loader->load('routing.xml');
+ $loader->load('templating.xml');
+ $loader->load('templating_php.xml');
+
+ if ($container->getParameter('kernel.debug')) {
+ $loader->load('templating_debug.xml');
}
- $container->setParameter('routing.resource', $config['router']['resource']);
+ if (isset($config['assets_version'])) {
+ $container->setParameter('templating.assets.version', $config['assets_version']);
+ }
- if (isset($config['router']['cache-warmer'])) {
- $config['router']['cache_warmer'] = $config['router']['cache-warmer'];
+ if (isset($config['assets_base_urls'])) {
+ $container->setParameter('templating.assets.base_urls', $config['assets_base_urls']);
}
- if (isset($config['router']['cache_warmer']) && $config['router']['cache_warmer']) {
- $container->getDefinition('router.cache_warmer')->addTag('kernel.cache_warmer');
- $container->setAlias('router', 'router.cached');
+ if (isset($config['loaders'])) {
+ $loaders = array_map(function($loader) { return new Reference($loader); }, $config['loaders']);
+
+ // Use a deligation unless only a single loader was registered
+ if (1 === count($loaders)) {
+ $container->setAlias('templating.loader', (string) reset($loaders));
+ } else {
+ $container->getDefinition('templating.loader.chain')->addArgument($loaders);
+ $container->setAlias('templating.loader', 'templating.loader.chain');
+ }
+ }
+
+ if (isset($config['cache'])) {
+ // Wrap the existing loader with cache (must happen after loaders are registered)
+ $container->setDefinition('templating.loader.wrapped', $container->findDefinition('templating.loader'));
+ $container->setDefinition('templating.loader', $container->getDefinition('templating.loader.cache'));
+ $container->setParameter('templating.loader.cache.path', $config['cache']);
+ } else {
+ $container->setParameter('templating.loader.cache.path', null);
+ }
+
+ if (isset($config['cache_warmer'])) {
+ $container->getDefinition('templating.cache_warmer.template_paths')->addTag('kernel.cache_warmer');
+ $container->setAlias('templating.locator', 'templating.locator.cached');
+ }
+
+ if (empty($config['engines'])) {
+ throw new \LogicException('You must register at least one templating engine.');
}
$this->addClassesToCompile(array(
- 'Symfony\\Component\\Routing\\RouterInterface',
- 'Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface',
- 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
- 'Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface',
- 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
- $container->findDefinition('router')->getClass()
+ 'Symfony\\Bundle\\FrameworkBundle\\Templating\\EngineInterface',
+ 'Symfony\\Component\\Templating\\EngineInterface',
+ 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\TemplateLocatorInterface',
+ $container->findDefinition('templating.locator')->getClass(),
));
+
+ if (in_array('php', $config['engines'], true)) {
+ $this->addClassesToCompile(array(
+ 'Symfony\\Component\\Templating\\PhpEngine',
+ 'Symfony\\Component\\Templating\\TemplateNameParserInterface',
+ 'Symfony\\Component\\Templating\\TemplateNameParser',
+ 'Symfony\\Component\\Templating\\Loader\\LoaderInterface',
+ 'Symfony\\Component\\Templating\\Storage\\Storage',
+ 'Symfony\\Component\\Templating\\Storage\\FileStorage',
+ 'Symfony\\Bundle\\FrameworkBundle\\Templating\\PhpEngine',
+ 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateNameParser',
+ 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\FilesystemLoader',
+ ));
+ }
+
+ $engines = array_map(function($engine) { return new Reference('templating.engine.'.$engine); }, $config['engines']);
+
+ // Use a deligation unless only a single engine was registered
+ if (1 === count($engines)) {
+ $container->setAlias('templating', (string) reset($engines));
+ } else {
+ $container->getDefinition('templating.engine.delegating')->setArgument(1, $engines);
+ $container->setAlias('templating', 'templating.engine.delegating');
+ }
}
/**
- * Loads the profiler configuration.
- *
- *
- *
- *
- *
- *
- *
- *
+ * Loads the translator configuration.
*
- * @param array $config A configuration array
+ * @param array $config A translator configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
*/
- protected function registerProfilerConfiguration(array $config, ContainerBuilder $container)
+ private function registerTranslatorConfiguration(array $config, ContainerBuilder $container)
{
- if ($config['profiler']) {
- if (!$container->hasDefinition('profiler')) {
- $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- $loader->load('profiling.xml');
- $loader->load('collectors.xml');
- }
+ if (isset($config['enabled']) && $config['enabled']) {
+ // Use the "real" translator instead of the identity default
+ $container->setDefinition('translator', $container->findDefinition('translator.real'));
- if (isset($config['profiler']['only-exceptions'])) {
- $container->setParameter('profiler_listener.only_exceptions', $config['profiler']['only-exceptions']);
- } elseif (isset($config['profiler']['only_exceptions'])) {
- $container->setParameter('profiler_listener.only_exceptions', $config['profiler']['only_exceptions']);
+ // Discover translation directories
+ $dirs = array();
+ foreach ($container->getParameter('kernel.bundles') as $bundle) {
+ $reflection = new \ReflectionClass($bundle);
+ if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) {
+ $dirs[] = $dir;
+ }
+ }
+ if (is_dir($dir = $container->getParameter('kernel.root_dir').'/translations')) {
+ $dirs[] = $dir;
}
- if (isset($config['profiler']['matcher'])) {
- if (isset($config['profiler']['matcher']['service'])) {
- $container->setAlias('profiler.request_matcher', $config['profiler']['matcher']['service']);
- } elseif (isset($config['profiler']['matcher']['_services'])) {
- $container->setAlias('profiler.request_matcher', (string) $config['profiler']['matcher']['_services'][0]);
- } else {
- $definition = $container->register('profiler.request_matcher', 'Symfony\\Component\\HttpFoundation\\RequestMatcher');
- $definition->setPublic(false);
-
- if (isset($config['profiler']['matcher']['ip'])) {
- $definition->addMethodCall('matchIp', array($config['profiler']['matcher']['ip']));
- }
-
- if (isset($config['profiler']['matcher']['path'])) {
- $definition->addMethodCall('matchPath', array($config['profiler']['matcher']['path']));
- }
+ // Register translation resources
+ $resources = array();
+ if ($dirs) {
+ $finder = new Finder();
+ $finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs);
+ foreach ($finder as $file) {
+ // filename is domain.locale.format
+ list($domain, $locale, $format) = explode('.', $file->getBasename());
+
+ $resources[] = array($format, (string) $file, $locale, $domain);
}
- } else {
- $container->removeAlias('profiler.request_matcher');
}
- } elseif ($container->hasDefinition('profiler')) {
- $container->getDefinition('profiling')->clearTags();
+ $container->setParameter('translation.resources', $resources);
+ }
+
+ if (isset($config['fallback'])) {
+ $container->setParameter('translator.fallback_locale', $config['fallback']);
}
}
/**
* Loads the validator configuration.
*
- * @param array $config A configuration array
+ * @param array $config A validation configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
+ * @param XmlFileLoader $loader An XmlFileLoader instance
*/
- protected function registerValidationConfiguration(array $config, ContainerBuilder $container)
+ private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
- if ($config['validation']['enabled']) {
- if (!$container->hasDefinition('validator')) {
- $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
- $loader->load('validator.xml');
- }
+ if (empty($config['enabled'])) {
+ return;
+ }
- $xmlMappingFiles = array();
- $yamlMappingFiles = array();
+ $loader->load('validator.xml');
- // default entries by the framework
- $xmlMappingFiles[] = __DIR__.'/../../../Component/Form/Resources/config/validation.xml';
+ $xmlMappingFiles = array();
+ $yamlMappingFiles = array();
- foreach ($container->getParameter('kernel.bundles') as $bundle) {
- $reflection = new \ReflectionClass($bundle);
- if (file_exists($file = dirname($reflection->getFilename()).'/Resources/config/validation.xml')) {
- $xmlMappingFiles[] = realpath($file);
- }
- if (file_exists($file = dirname($reflection->getFilename()).'/Resources/config/validation.yml')) {
- $yamlMappingFiles[] = realpath($file);
- }
+ // Include default entries from the framework
+ $xmlMappingFiles[] = __DIR__.'/../../../Component/Form/Resources/config/validation.xml';
+
+ foreach ($container->getParameter('kernel.bundles') as $bundle) {
+ $reflection = new \ReflectionClass($bundle);
+ if (file_exists($file = dirname($reflection->getFilename()).'/Resources/config/validation.xml')) {
+ $xmlMappingFiles[] = realpath($file);
}
+ if (file_exists($file = dirname($reflection->getFilename()).'/Resources/config/validation.yml')) {
+ $yamlMappingFiles[] = realpath($file);
+ }
+ }
- $xmlFilesLoader = new Definition(
- $container->getParameter('validator.mapping.loader.xml_files_loader.class'),
- array($xmlMappingFiles)
- );
- $xmlFilesLoader->setPublic(false);
+ $xmlFilesLoader = new Definition('%validator.mapping.loader.xml_files_loader.class%', array($xmlMappingFiles));
+ $xmlFilesLoader->setPublic(false);
- $yamlFilesLoader = new Definition(
- $container->getParameter('validator.mapping.loader.yaml_files_loader.class'),
- array($yamlMappingFiles)
- );
- $yamlFilesLoader->setPublic(false);
+ $yamlFilesLoader = new Definition('%validator.mapping.loader.yaml_files_loader.class%', array($yamlMappingFiles));
+ $yamlFilesLoader->setPublic(false);
- $container->setDefinition('validator.mapping.loader.xml_files_loader', $xmlFilesLoader);
- $container->setDefinition('validator.mapping.loader.yaml_files_loader', $yamlFilesLoader);
+ $container->setDefinition('validator.mapping.loader.xml_files_loader', $xmlFilesLoader);
+ $container->setDefinition('validator.mapping.loader.yaml_files_loader', $yamlFilesLoader);
- foreach ($xmlMappingFiles as $file) {
- $container->addResource(new FileResource($file));
- }
+ foreach ($xmlMappingFiles as $file) {
+ $container->addResource(new FileResource($file));
+ }
- foreach ($yamlMappingFiles as $file) {
- $container->addResource(new FileResource($file));
- }
+ foreach ($yamlMappingFiles as $file) {
+ $container->addResource(new FileResource($file));
+ }
- if (isset($config['validation']['annotations'])) {
- if (isset($config['validation']['annotations']['namespaces']) && is_array($config['validation']['annotations']['namespaces'])) {
- $container->setParameter('validator.annotations.namespaces', array_merge(
- $container->getParameter('validator.annotations.namespaces'),
- $config['validation']['annotations']['namespaces']
- ));
- }
+ if (isset($config['annotations'])) {
+ // Register prefixes for constraint namespaces
+ if (!empty($config['annotations']['namespaces'])) {
+ $container->setParameter('validator.annotations.namespaces', array_merge(
+ $container->getParameter('validator.annotations.namespaces'),
+ $config['annotations']['namespaces']
+ ));
+ }
- $annotationLoader = new Definition($container->getParameter('validator.mapping.loader.annotation_loader.class'));
- $annotationLoader->setPublic(false);
- $annotationLoader->addArgument(new Parameter('validator.annotations.namespaces'));
+ // Register annotation loader
+ $annotationLoader = new Definition('%validator.mapping.loader.annotation_loader.class%');
+ $annotationLoader->setPublic(false);
+ $annotationLoader->addArgument(new Parameter('validator.annotations.namespaces'));
- $container->setDefinition('validator.mapping.loader.annotation_loader', $annotationLoader);
+ $container->setDefinition('validator.mapping.loader.annotation_loader', $annotationLoader);
- $loader = $container->getDefinition('validator.mapping.loader.loader_chain');
- $arguments = $loader->getArguments();
- array_unshift($arguments[0], new Reference('validator.mapping.loader.annotation_loader'));
- $loader->setArguments($arguments);
- }
- } elseif ($container->hasDefinition('validator')) {
- $container->getDefinition('validator')->clearTags();
+ $loaderChain = $container->getDefinition('validator.mapping.loader.loader_chain');
+ $arguments = $loaderChain->getArguments();
+ array_unshift($arguments[0], new Reference('validator.mapping.loader.annotation_loader'));
+ $loaderChain->setArguments($arguments);
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index fc15e0804ff83..c7a5577ef7a2e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -80,20 +80,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index a70f035342b6d..689185a4610c0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -9,34 +9,50 @@
-
-
+
+
+
-
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -47,15 +63,9 @@
-
-
-
-
-
-
@@ -64,11 +74,14 @@
-
-
+
+
+
+
+
@@ -83,21 +96,26 @@
-
-
+
+
-
+
-
-
+
-
+
+
+
+
+
+
-
-
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/skeleton/bundle/Bundle.php b/src/Symfony/Bundle/FrameworkBundle/Resources/skeleton/bundle/Bundle.php
index 2c101de81610a..7721df5248599 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/skeleton/bundle/Bundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/skeleton/bundle/Bundle.php
@@ -6,19 +6,4 @@
class {{ bundle }} extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return strtr(__DIR__, '\\', '/');
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
new file mode 100644
index 0000000000000..20a272c4c78a2
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
@@ -0,0 +1,45 @@
+loadFromExtension('app', 'config', array(
+ 'csrf_protection' => array(
+ 'enabled' => true,
+ 'field_name' => '_csrf',
+ 'secret' => 's3cr3t',
+ ),
+ 'esi' => array(
+ 'enabled' => true,
+ ),
+ 'profiler' => array(
+ 'only_exceptions' => true,
+ ),
+ 'router' => array(
+ 'resource' => '%kernel.root_dir%/config/routing.xml',
+ 'cache_warmer' => true,
+ ),
+ 'session' => array(
+ 'auto_start' => true,
+ 'class' => 'Session',
+ 'default_locale' => 'fr',
+ 'storage_id' => 'native',
+ 'name' => '_SYMFONY',
+ 'lifetime' => 86400,
+ 'path' => '/',
+ 'domain' => 'example.com',
+ 'secure' => true,
+ 'httponly' => true,
+ ),
+ 'templating' => array(
+ 'assets_version' => 'SomeVersionScheme',
+ 'assets_base_urls' => 'http://cdn.example.com',
+ 'cache_warmer' => true,
+ 'engines' => array('php', 'twig'),
+ 'loader' => array('loader.foo', 'loader.bar'),
+ ),
+ 'translator' => array(
+ 'enabled' => true,
+ 'fallback' => 'fr',
+ ),
+ 'validation' => array(
+ 'enabled' => true,
+ ),
+));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/session_pdo.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/session_pdo.php
new file mode 100644
index 0000000000000..eb8deb9d1f01f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/session_pdo.php
@@ -0,0 +1,11 @@
+loadFromExtension('app', 'config', array(
+ 'session' => array(
+ 'storage_id' => 'pdo',
+ 'pdo.db_table' => 'table',
+ 'pdo.db_id_col' => 'id',
+ 'pdo.db_data_col' => 'data',
+ 'pdo.db_time_col' => 'time',
+ ),
+));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_annotations.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_annotations.php
new file mode 100644
index 0000000000000..bed6c991b44d2
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_annotations.php
@@ -0,0 +1,12 @@
+loadFromExtension('app', 'config', array(
+ 'validation' => array(
+ 'enabled' => true,
+ 'annotations' => array(
+ 'namespaces' => array(
+ 'app' => 'Application\\Validator\\Constraints\\',
+ ),
+ ),
+ ),
+));
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
new file mode 100644
index 0000000000000..ebc2f39fe6368
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+ loader.foo
+ loader.bar
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/session_pdo.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/session_pdo.xml
new file mode 100644
index 0000000000000..84455afff6d0c
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/session_pdo.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_annotations.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_annotations.xml
new file mode 100644
index 0000000000000..1af18e148f7f2
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_annotations.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
new file mode 100644
index 0000000000000..bb8d3bc3bc90e
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
@@ -0,0 +1,34 @@
+app.config:
+ csrf_protection:
+ enabled: true
+ field_name: _csrf
+ secret: s3cr3t
+ esi:
+ enabled: true
+ profiler:
+ only_exceptions: true
+ router:
+ resource: %kernel.root_dir%/config/routing.xml
+ cache_warmer: true
+ session:
+ auto_start: true
+ class: Session
+ default_locale: fr
+ storage_id: native
+ name: _SYMFONY
+ lifetime: 86400
+ path: /
+ domain: example.com
+ secure: true
+ httponly: true
+ templating:
+ assets_version: SomeVersionScheme
+ assets_base_urls: http://cdn.example.com
+ cache_warmer: true
+ engines: [php, twig]
+ loader: [loader.foo, loader.bar]
+ translator:
+ enabled: true
+ fallback: fr
+ validation:
+ enabled: true
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/session_pdo.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/session_pdo.yml
new file mode 100644
index 0000000000000..06323d53de9b4
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/session_pdo.yml
@@ -0,0 +1,7 @@
+app.config:
+ session:
+ storage_id: pdo
+ pdo.db_table: table
+ pdo.db_id_col: id
+ pdo.db_data_col: data
+ pdo.db_time_col: time
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_annotations.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_annotations.yml
new file mode 100644
index 0000000000000..1ff2545facb94
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_annotations.yml
@@ -0,0 +1,6 @@
+app.config:
+ validation:
+ enabled: true
+ annotations:
+ namespaces:
+ app: Application\Validator\Constraints\
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 0e83eb1ff8169..99da686fa3969 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -16,43 +16,182 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
-class FrameworkExtensionTest extends TestCase
+abstract class FrameworkExtensionTest extends TestCase
{
- public function testConfigLoad()
+ abstract protected function loadFromFile(ContainerBuilder $container, $file);
+
+ public function testCsrfProtection()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->getParameter('form.csrf_protection.enabled'));
+ $this->assertEquals('_csrf', $container->getParameter('form.csrf_protection.field_name'));
+ $this->assertEquals('s3cr3t', $container->getParameter('form.csrf_protection.secret'));
+ }
+
+ public function testEsi()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->hasDefinition('esi'), '->registerEsiConfiguration() loads esi.xml');
+ }
+
+ public function testProfiler()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->hasDefinition('profiler'), '->registerProfilerConfiguration() loads profiling.xml');
+ $this->assertTrue($container->hasDefinition('data_collector.config'), '->registerProfilerConfiguration() loads collectors.xml');
+ $this->assertTrue($container->getParameter('profiler_listener.only_exceptions'));
+ }
+
+ public function testRouter()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->hasDefinition('router.real'), '->registerRouterConfiguration() loads routing.xml');
+ $this->assertEquals($container->getParameter('kernel.root_dir').'/config/routing.xml', $container->getParameter('routing.resource'), '->registerRouterConfiguration() sets routing resource');
+ $this->assertTrue($container->getDefinition('router.cache_warmer')->hasTag('kernel.cache_warmer'), '->registerRouterConfiguration() tags router cache warmer if cache warming is set');
+ $this->assertEquals('router.cached', (string) $container->getAlias('router'), '->registerRouterConfiguration() changes router alias to cached if cache warming is set');
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testRouterRequiresResourceOption()
{
- $container = $this->getContainer();
+ $container = $this->createContainer();
$loader = new FrameworkExtension();
+ $loader->configLoad(array(array('router' => true)), $container);
+ }
+
+ public function testSession()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->hasDefinition('session'), '->registerSessionConfiguration() loads session.xml');
+ $this->assertEquals('fr', $container->getParameter('session.default_locale'));
+ $this->assertTrue($container->getDefinition('session')->hasMethodCall('start'));
+ $this->assertEquals('Session', $container->getParameter('session.class'));
+ $this->assertEquals('session.storage.native', (string) $container->getAlias('session.storage'));
+
+ $options = $container->getParameter('session.storage.native.options');
+ $this->assertEquals('_SYMFONY', $options['name']);
+ $this->assertEquals(86400, $options['lifetime']);
+ $this->assertEquals('/', $options['path']);
+ $this->assertEquals('example.com', $options['domain']);
+ $this->assertTrue($options['secure']);
+ $this->assertTrue($options['httponly']);
+ }
+
+ public function testSessionPdo()
+ {
+ $container = $this->createContainerFromFile('session_pdo');
+ $options = $container->getParameter('session.storage.pdo.options');
+
+ $this->assertEquals('session.storage.pdo', (string) $container->getAlias('session.storage'));
+ $this->assertEquals('table', $options['db_table']);
+ $this->assertEquals('id', $options['db_id_col']);
+ $this->assertEquals('data', $options['db_data_col']);
+ $this->assertEquals('time', $options['db_time_col']);
+ }
+
+ public function testTemplating()
+ {
+ $container = $this->createContainerFromFile('full');
- $loader->configLoad(array(array()), $container);
- $this->assertEquals('Symfony\\Bundle\\FrameworkBundle\\RequestListener', $container->getParameter('request_listener.class'), '->webLoad() loads the web.xml file if not already loaded');
+ $this->assertTrue($container->hasDefinition('templating.name_parser'), '->registerTemplatingConfiguration() loads templating.xml');
+ $this->assertEquals('SomeVersionScheme', $container->getParameter('templating.assets.version'));
+ $this->assertEquals('http://cdn.example.com', $container->getParameter('templating.assets.base_urls'));
- $container = $this->getContainer();
+ $this->assertTrue($container->getDefinition('templating.cache_warmer.template_paths')->hasTag('kernel.cache_warmer'), '->registerTemplatingConfiguration() tags templating cache warmer if cache warming is set');
+ $this->assertEquals('templating.locator.cached', (string) $container->getAlias('templating.locator'), '->registerTemplatingConfiguration() changes templating.locator alias to cached if cache warming is set');
+
+ $this->assertEquals('templating.engine.delegating', (string) $container->getAlias('templating'), '->registerTemplatingConfiguration() configures delegating loader if multiple engines are provided');
+
+ $this->assertEquals('templating.loader.chain', (string) $container->getAlias('templating.loader'), '->registerTemplatingConfiguration() configures loader chain if multiple loaders are provided');
+ }
+
+ public function testTranslator()
+ {
+ $container = $this->createContainerFromFile('full');
+
+ $this->assertTrue($container->hasDefinition('translator.real'), '->registerTranslatorConfiguration() loads translation.xml');
+ $this->assertSame($container->getDefinition('translator.real'), $container->getDefinition('translator'), '->registerTranslatorConfiguration() redefines translator service from identity to real translator');
+
+ $this->assertContains(
+ realpath(__DIR__.'/../../Resources/translations/validators.fr.xliff'),
+ array_map(function($resource) { return $resource[1]; }, $container->getParameter('translation.resources')),
+ '->registerTranslatorConfiguration() finds FrameworkExtension translation resources'
+ );
+
+ $this->assertEquals('fr', $container->getParameter('translator.fallback_locale'));
+ }
+
+ /**
+ * @expectedException LogicException
+ */
+ public function testTemplatingRequiresAtLeastOneEngine()
+ {
+ $container = $this->createContainer();
$loader = new FrameworkExtension();
+ $loader->configLoad(array(array('templating' => null)), $container);
+ }
+
+ public function testValidation()
+ {
+ $container = $this->createContainerFromFile('full');
- // profiler
- $loader->configLoad(array(array('profiler' => true)), $container);
- $this->assertEquals('Symfony\Component\HttpKernel\Profiler\Profiler', $container->getParameter('profiler.class'), '->configLoad() loads the collectors.xml file if not already loaded');
+ $this->assertTrue($container->hasDefinition('validator'), '->registerValidationConfiguration() loads validator.xml');
+ $this->assertTrue($container->hasDefinition('validator.mapping.loader.xml_files_loader'), '->registerValidationConfiguration() defines the XML loader');
+ $this->assertTrue($container->hasDefinition('validator.mapping.loader.yaml_files_loader'), '->registerValidationConfiguration() defines the YAML loader');
- // templating
- $loader->configLoad(array(array('templating' => array('engines' => array('php')))), $container);
- $this->assertEquals('Symfony\\Bundle\\FrameworkBundle\\Templating\\PhpEngine', $container->getParameter('templating.engine.php.class'), '->templatingLoad() loads the templating.xml file if not already loaded');
+ $xmlLoaderArgs = $container->getDefinition('validator.mapping.loader.xml_files_loader')->getArguments();
+ $xmlFiles = $xmlLoaderArgs[0];
- // validation
- $loader->configLoad(array(array('validation' => array('enabled' => true))), $container);
- $this->assertEquals('Symfony\Component\Validator\Validator', $container->getParameter('validator.class'), '->validationLoad() loads the validation.xml file if not already loaded');
- $this->assertFalse($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->validationLoad() doesn\'t load the annotations service unless its needed');
+ $this->assertContains(
+ realpath(__DIR__.'/../../../../Component/Form/Resources/config/validation.xml'),
+ array_map('realpath', $xmlFiles),
+ '->registerValidationConfiguration() adds Form validation.xml to XML loader'
+ );
- $loader->configLoad(array(array('validation' => array('enabled' => true, 'annotations' => true))), $container);
- $this->assertTrue($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->validationLoad() loads the annotations service');
+ $this->assertFalse($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->registerValidationConfiguration() does not define the annotation loader unless needed');
}
- protected function getContainer()
+ public function testValidationAnnotations()
+ {
+ $container = $this->createContainerFromFile('validation_annotations');
+
+ $this->assertTrue($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->registerValidationConfiguration() defines the annotation loader');
+
+ $namespaces = $container->getParameter('validator.annotations.namespaces');
+ $this->assertEquals('Symfony\\Component\\Validator\\Constraints\\', $namespaces['validation'], '->registerValidationConfiguration() loads the default "validation" namespace');
+ $this->assertEquals('Application\\Validator\\Constraints\\', $namespaces['app'], '->registerValidationConfiguration() loads custom validation namespaces');
+ }
+
+ protected function createContainer()
{
return new ContainerBuilder(new ParameterBag(array(
'kernel.bundles' => array('FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'),
- 'kernel.root_dir' => __DIR__,
- 'kernel.debug' => false,
+ 'kernel.cache_dir' => __DIR__,
'kernel.compiled_classes' => array(),
+ 'kernel.debug' => false,
+ 'kernel.environment' => 'test',
+ 'kernel.name' => 'kernel',
+ 'kernel.root_dir' => __DIR__,
)));
}
+
+ protected function createContainerFromFile($file)
+ {
+ $container = $this->createContainer();
+ $container->registerExtension(new FrameworkExtension());
+ $this->loadFromFile($container, $file);
+
+ $container->getCompilerPassConfig()->setOptimizationPasses(array());
+ $container->getCompilerPassConfig()->setRemovingPasses(array());
+ $container->compile();
+
+ return $container;
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
new file mode 100644
index 0000000000000..451d16364a329
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
+
+class PhpFrameworkExtensionTest extends FrameworkExtensionTest
+{
+ protected function loadFromFile(ContainerBuilder $container, $file)
+ {
+ $loader = new PhpFileLoader($container, __DIR__.'/Fixtures/php');
+ $loader->load($file.'.php');
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php
new file mode 100644
index 0000000000000..ea6fbe08a7335
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/XmlFrameworkExtensionTest.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+
+class XmlFrameworkExtensionTest extends FrameworkExtensionTest
+{
+ protected function loadFromFile(ContainerBuilder $container, $file)
+ {
+ $loader = new XmlFileLoader($container, __DIR__.'/Fixtures/xml');
+ $loader->load($file.'.xml');
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/YamlFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/YamlFrameworkExtensionTest.php
new file mode 100644
index 0000000000000..c1af39109e980
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/YamlFrameworkExtensionTest.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+
+class YamlFrameworkExtensionTest extends FrameworkExtensionTest
+{
+ protected function loadFromFile(ContainerBuilder $container, $file)
+ {
+ $loader = new YamlFileLoader($container, __DIR__.'/Fixtures/yml');
+ $loader->load($file.'.yml');
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Fabpot/FooBundle/FabpotFooBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Fabpot/FooBundle/FabpotFooBundle.php
index 1342b9b5eed32..22b95430711fc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Fabpot/FooBundle/FabpotFooBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Fabpot/FooBundle/FabpotFooBundle.php
@@ -27,20 +27,4 @@ public function getParent()
{
return 'SensioFooBundle';
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/FooBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/FooBundle.php
index 98dd4342273a2..af57d44bcdd2f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/FooBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/FooBundle/FooBundle.php
@@ -20,19 +20,4 @@
*/
class FooBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/Cms/FooBundle/SensioCmsFooBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/Cms/FooBundle/SensioCmsFooBundle.php
index 811ed2f14115a..9e6918d34e955 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/Cms/FooBundle/SensioCmsFooBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/Cms/FooBundle/SensioCmsFooBundle.php
@@ -20,19 +20,4 @@
*/
class SensioCmsFooBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/FooBundle/SensioFooBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/FooBundle/SensioFooBundle.php
index 2b547f923ece1..e8930625f3b19 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/FooBundle/SensioFooBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/TestBundle/Sensio/FooBundle/SensioFooBundle.php
@@ -20,19 +20,4 @@
*/
class SensioFooBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Configuration.php
new file mode 100644
index 0000000000000..5f48157cb313e
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Configuration.php
@@ -0,0 +1,234 @@
+
+ */
+class Configuration
+{
+ public function getAclConfigTree()
+ {
+ $tb = new TreeBuilder();
+
+ return $tb
+ ->root('security:acl', 'array')
+ ->scalarNode('connection')->end()
+ ->scalarNode('cache')->end()
+ ->end()
+ ->buildTree();
+ }
+
+ public function getFactoryConfigTree()
+ {
+ $tb = new TreeBuilder();
+
+ return $tb
+ ->root('security:config', 'array')
+ ->fixXmlConfig('factory', 'factories')
+ ->arrayNode('factories')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->buildTree();
+ }
+
+ public function getMainConfigTree(array $factories)
+ {
+ $tb = new TreeBuilder();
+ $rootNode = $tb->root('security:config', 'array');
+
+ $rootNode
+ ->scalarNode('access_denied_url')->end()
+ ->scalarNode('session_fixation_strategy')->cannotBeEmpty()->defaultValue('migrate')->end()
+ ;
+
+ $this->addEncodersSection($rootNode);
+ $this->addProvidersSection($rootNode);
+ $this->addFirewallsSection($rootNode, $factories);
+ $this->addAccessControlSection($rootNode);
+ $this->addRoleHierarchySection($rootNode);
+
+ return $tb->buildTree();
+ }
+
+ protected function addRoleHierarchySection($rootNode)
+ {
+ $rootNode
+ ->fixXmlConfig('role', 'role_hierarchy')
+ ->arrayNode('role_hierarchy')
+ ->containsNameValuePairsWithKeyAttribute('id')
+ ->prototype('array')
+ ->beforeNormalization()->ifString()->then(function($v) { return array('value' => $v); })->end()
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && isset($v['value']); })
+ ->then(function($v) { return preg_split('/\s*,\s*/', $v['value']); })
+ ->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ;
+ }
+
+ protected function addAccessControlSection($rootNode)
+ {
+ $rootNode
+ ->fixXmlConfig('rule', 'access_control')
+ ->arrayNode('access_control')
+ ->cannotBeOverwritten()
+ ->prototype('array')
+ ->scalarNode('requires_channel')->defaultNull()->end()
+ ->scalarNode('path')->defaultNull()->end()
+ ->scalarNode('host')->defaultNull()->end()
+ ->scalarNode('ip')->defaultNull()->end()
+ ->arrayNode('methods')
+ ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->fixXmlConfig('role')
+ ->arrayNode('roles')
+ ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->fixXmlConfig('attribute')
+ ->arrayNode('attributes')
+ ->containsNameValuePairsWithKeyAttribute('key')
+ ->prototype('scalar')
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && isset($v['pattern']); })
+ ->then(function($v) { return $v['pattern']; })
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+ }
+
+ protected function addFirewallsSection($rootNode, array $factories)
+ {
+ $firewallNodeBuilder =
+ $rootNode
+ ->fixXmlConfig('firewall')
+ ->arrayNode('firewalls')
+ ->disallowNewKeysInSubsequentConfigs()
+ ->useAttributeAsKey('name')
+ ->prototype('array')
+ ->scalarNode('pattern')->end()
+ ->booleanNode('security')->defaultTrue()->end()
+ ->scalarNode('request_matcher')->end()
+ ->scalarNode('access_denied_url')->end()
+ ->scalarNode('access_denied_handler')->end()
+ ->scalarNode('entry_point')->end()
+ ->scalarNode('provider')->end()
+ ->booleanNode('stateless')->defaultFalse()->end()
+ ->scalarNode('context')->cannotBeEmpty()->end()
+ ->arrayNode('logout')
+ ->treatTrueLike(array())
+ ->canBeUnset()
+ ->scalarNode('path')->defaultValue('/logout')->end()
+ ->scalarNode('target')->defaultValue('/')->end()
+ ->booleanNode('invalidate_session')->defaultTrue()->end()
+ ->fixXmlConfig('delete_cookie')
+ ->arrayNode('delete_cookies')
+ ->beforeNormalization()
+ ->ifTrue(function($v) { return is_array($v) && is_int(key($v)); })
+ ->then(function($v) { return array_map(function($v) { return array('name' => $v); }, $v); })
+ ->end()
+ ->useAttributeAsKey('name')
+ ->prototype('array')
+ ->scalarNode('path')->defaultNull()->end()
+ ->scalarNode('domain')->defaultNull()->end()
+ ->end()
+ ->end()
+ ->fixXmlConfig('handler')
+ ->arrayNode('handlers')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->booleanNode('anonymous')->end()
+ ->arrayNode('switch_user')
+ ->scalarNode('provider')->end()
+ ->scalarNode('parameter')->defaultValue('_switch_user')->end()
+ ->scalarNode('role')->defaultValue('ROLE_ALLOWED_TO_SWITCH')->end()
+ ->end()
+ ;
+
+ foreach ($factories as $factoriesAtPosition) {
+ foreach ($factoriesAtPosition as $factory) {
+ $factoryNode =
+ $firewallNodeBuilder->arrayNode(str_replace('-', '_', $factory->getKey()))
+ ->canBeUnset()
+ ;
+
+ $factory->addConfiguration($factoryNode);
+ }
+ }
+ }
+
+ protected function addProvidersSection($rootNode)
+ {
+ $rootNode
+ ->fixXmlConfig('provider')
+ ->arrayNode('providers')
+ ->disallowNewKeysInSubsequentConfigs()
+ ->requiresAtLeastOneElement()
+ ->useAttributeAsKey('name')
+ ->prototype('array')
+ ->scalarNode('id')->end()
+ ->fixXmlConfig('provider')
+ ->arrayNode('providers')
+ ->prototype('scalar')->end()
+ ->end()
+ ->fixXmlConfig('user')
+ ->arrayNode('users')
+ ->useAttributeAsKey('name')
+ ->prototype('array')
+ ->scalarNode('password')->defaultValue(uniqid())->end()
+ ->arrayNode('roles')
+ ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('entity')
+ ->scalarNode('class')->isRequired()->cannotBeEmpty()->end()
+ ->scalarNode('property')->defaultNull()->end()
+ ->end()
+ ->arrayNode('document')
+ ->scalarNode('class')->isRequired()->cannotBeEmpty()->end()
+ ->scalarNode('property')->defaultNull()->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+ }
+
+ protected function addEncodersSection($rootNode)
+ {
+ $rootNode
+ ->fixXmlConfig('encoder')
+ ->arrayNode('encoders')
+ ->useAttributeAsKey('class')
+ ->prototype('array')
+ ->beforeNormalization()->ifString()->then(function($v) { return array('algorithm' => $v); })->end()
+ ->scalarNode('algorithm')->isRequired()->cannotBeEmpty()->end()
+ ->booleanNode('ignore_case')->end()
+ ->booleanNode('encode_as_base64')->end()
+ ->scalarNode('iterations')->end()
+ ->scalarNode('id')->end()
+ ->end()
+ ->end()
+ ;
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
index 860ba9e145b99..88b481e3b1f16 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -38,10 +40,6 @@ abstract class AbstractFactory implements SecurityFactoryInterface
public function create(ContainerBuilder $container, $id, $config, $userProviderId, $defaultEntryPointId)
{
- if (!is_array($config)) {
- $config = array();
- }
-
// authentication provider
$authProviderId = $this->createAuthProvider($container, $id, $config, $userProviderId);
$container
@@ -66,6 +64,24 @@ public function create(ContainerBuilder $container, $id, $config, $userProviderI
return array($authProviderId, $listenerId, $entryPointId);
}
+ public function addConfiguration(NodeBuilder $node)
+ {
+ $node
+ ->scalarNode('provider')->end()
+ ->booleanNode('remember_me')->defaultTrue()->end()
+ ->scalarNode('success_handler')->end()
+ ->scalarNode('failure_handler')->end()
+ ;
+
+ foreach ($this->options as $name => $default) {
+ if (is_bool($default)) {
+ $node->booleanNode($name)->defaultValue($default);
+ } else {
+ $node->scalarNode($name)->defaultValue($default);
+ }
+ }
+ }
+
public final function addOption($name, $default = null)
{
$this->options[$name] = $default;
@@ -127,18 +143,15 @@ protected function createEntryPoint($container, $id, $config, $defaultEntryPoint
*/
protected function isRememberMeAware($config)
{
- return !isset($config['remember_me']) || (Boolean) $config['remember_me'];
+ return $config['remember_me'];
}
protected function createListener($container, $id, $config, $userProvider)
{
- // merge set options with default options
- $options = $this->getOptionsFromConfig($config);
-
$listenerId = $this->getListenerId();
$listener = new DefinitionDecorator($listenerId);
$listener->setArgument(3, $id);
- $listener->setArgument(4, $options);
+ $listener->setArgument(4, array_intersect_key($config, $this->options));
// success handler
if (isset($config['success_handler'])) {
@@ -155,17 +168,4 @@ protected function createListener($container, $id, $config, $userProvider)
return $listenerId;
}
-
- protected final function getOptionsFromConfig($config)
- {
- $options = $this->options;
-
- foreach (array_keys($options) as $key) {
- if (array_key_exists($key, $config)) {
- $options[$key] = $config[$key];
- }
- }
-
- return $options;
- }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php
index 6149361fb8871..eef9aecdc4251 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php
@@ -59,14 +59,11 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config,
protected function createEntryPoint($container, $id, $config, $defaultEntryPoint)
{
- // merge set options with default options
- $options = $this->getOptionsFromConfig($config);
-
$entryPointId = 'security.authentication.form_entry_point.'.$id;
$container
->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point'))
- ->addArgument($options['login_path'])
- ->addArgument($options['use_forward'])
+ ->addArgument($config['login_path'])
+ ->addArgument($config['use_forward'])
;
return $entryPointId;
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php
index 3686a1e06f1d2..9b2b7a870a864 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -53,4 +55,11 @@ public function getKey()
{
return 'http-basic';
}
+
+ public function addConfiguration(NodeBuilder $builder)
+ {
+ $builder
+ ->scalarNode('provider')->end()
+ ;
+ }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php
index d837032e41096..49cf748cf40e9 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpDigestFactory.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -53,4 +55,11 @@ public function getKey()
{
return 'http-digest';
}
+
+ public function addConfiguration(NodeBuilder $builder)
+ {
+ $builder
+ ->scalarNode('provider')->end()
+ ;
+ }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
index e8646e90d09a6..c4727429ab5e3 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
@@ -2,6 +2,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
@@ -10,16 +12,19 @@
class RememberMeFactory implements SecurityFactoryInterface
{
+ protected $options = array(
+ 'name' => 'REMEMBERME',
+ 'lifetime' => 31536000,
+ 'path' => '/',
+ 'domain' => null,
+ 'secure' => false,
+ 'httponly' => true,
+ 'always_remember_me' => false,
+ 'remember_me_parameter' => '_remember_me',
+ );
+
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
- if (!isset($config['key']) || empty($config['key'])) {
- throw new \RuntimeException('A "key" must be defined for each remember-me section.');
- }
-
- if (isset($config['provider'])) {
- throw new \RuntimeException('You must not set a user provider for remember-me.');
- }
-
// authentication provider
$authProviderId = 'security.authentication.provider.rememberme.'.$id;
$container
@@ -60,22 +65,7 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider,
}
// remember-me options
- $options = array(
- 'name' => 'REMEMBERME',
- 'lifetime' => 31536000,
- 'path' => '/',
- 'domain' => null,
- 'secure' => false,
- 'httponly' => true,
- 'always_remember_me' => false,
- 'remember_me_parameter' => '_remember_me',
- );
- foreach ($options as $name => $option) {
- if (array_key_exists($name, $config)) {
- $options[$name] = $config[$name];
- }
- }
- $rememberMeServices->setArgument(3, $options);
+ $rememberMeServices->setArgument(3, array_intersect_key($config, $this->options));
// attach to remember-me aware listeners
$userProviders = array();
@@ -118,4 +108,20 @@ public function getKey()
{
return 'remember-me';
}
+
+ public function addConfiguration(NodeBuilder $node)
+ {
+ $node
+ ->scalarNode('key')->isRequired()->cannotBeEmpty()->end()
+ ->scalarNode('token_provider')->end()
+ ;
+
+ foreach ($this->options as $name => $value) {
+ if (is_bool($value)) {
+ $node->booleanNode($name)->defaultValue($value);
+ } else {
+ $node->scalarNode($name)->defaultValue($value);
+ }
+ }
+ }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php
index a2ec07df051ce..05dcc74f8a4c8 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php
@@ -11,6 +11,7 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
@@ -25,4 +26,6 @@ function create(ContainerBuilder $container, $id, $config, $userProvider, $defau
function getPosition();
function getKey();
+
+ function addConfiguration(NodeBuilder $builder);
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php
index dbf0e359148ac..d53f75d978ca8 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
+use Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder;
+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -50,4 +52,11 @@ public function getKey()
{
return 'x509';
}
+
+ public function addConfiguration(NodeBuilder $builder)
+ {
+ $builder
+ ->scalarNode('provider')->end()
+ ;
+ }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
index edc27e69f21da..ac835082bd1a8 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
+use Symfony\Component\DependencyInjection\Configuration\Processor;
+use Symfony\Component\DependencyInjection\Configuration\Builder\TreeBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@@ -34,44 +36,38 @@ class SecurityExtension extends Extension
protected $requestMatchers = array();
protected $contextListeners = array();
protected $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me');
+ protected $configuration;
+ protected $factories;
- public function configLoad(array $configs, ContainerBuilder $container)
+ public function __construct()
{
- foreach ($configs as $config) {
- $this->doConfigLoad($this->normalizeKeys($config), $container);
- }
+ $this->configuration = new Configuration();
}
- public function aclLoad(array $configs, ContainerBuilder $container)
+ public function configLoad(array $configs, ContainerBuilder $container)
{
- foreach ($configs as $config) {
- $this->doAclLoad($this->normalizeKeys($config), $container);
- }
- }
+ $processor = new Processor();
- /**
- * Loads the web configuration.
- *
- * @param array $config An array of configuration settings
- * @param ContainerBuilder $container A ContainerBuilder instance
- */
- protected function doConfigLoad($config, ContainerBuilder $container)
- {
- if (!$container->hasDefinition('security.context')) {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('security.xml');
- $loader->load('security_listeners.xml');
- $loader->load('security_rememberme.xml');
- $loader->load('templating_php.xml');
- $loader->load('templating_twig.xml');
- $loader->load('collectors.xml');
- }
+ // first assemble the factories
+ $factories = $this->createListenerFactories($container, $processor->process($this->configuration->getFactoryConfigTree(), $configs));
+
+ // normalize and merge the actual configuration
+ $tree = $this->configuration->getMainConfigTree($factories);
+ $config = $processor->process($tree, $configs);
+ // load services
+ $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
+ $loader->load('security.xml');
+ $loader->load('security_listeners.xml');
+ $loader->load('security_rememberme.xml');
+ $loader->load('templating_php.xml');
+ $loader->load('templating_twig.xml');
+ $loader->load('collectors.xml');
+
+ // set some global scalars
if (isset($config['access_denied_url'])) {
$container->setParameter('security.access.denied_url', $config['access_denied_url']);
}
-
- // session fixation protection
if (isset($config['session_fixation_protection'])) {
$container->setParameter('security.authentication.session_strategy.strategy', $config['session_fixation_protection']);
}
@@ -79,97 +75,95 @@ protected function doConfigLoad($config, ContainerBuilder $container)
$this->createFirewalls($config, $container);
$this->createAuthorization($config, $container);
$this->createRoleHierarchy($config, $container);
-
- return $container;
}
- protected function createRoleHierarchy($config, ContainerBuilder $container)
+ public function aclLoad(array $configs, ContainerBuilder $container)
{
- $roles = array();
- if (isset($config['role_hierarchy'])) {
- $roles = $config['role_hierarchy'];
+ $processor = new Processor();
+ $config = $processor->process($this->configuration->getAclConfigTree(), $configs);
+
+ $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
+ $loader->load('security_acl.xml');
+
+ if (isset($config['connection'])) {
+ $container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
}
- if (isset($roles['role']) && is_int(key($roles['role']))) {
- $roles = $roles['role'];
+ if (isset($config['cache'])) {
+ $container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
}
+ }
- $hierarchy = array();
- foreach ($roles as $id => $role) {
- if (is_array($role) && isset($role['id'])) {
- $id = $role['id'];
- }
+ /**
+ * Returns the base path for the XSD files.
+ *
+ * @return string The XSD base path
+ */
+ public function getXsdValidationBasePath()
+ {
+ return __DIR__.'/../Resources/config/schema';
+ }
- $value = $role;
- if (is_array($role) && isset($role['value'])) {
- $value = $role['value'];
- }
+ public function getNamespace()
+ {
+ return 'http://www.symfony-project.org/schema/dic/security';
+ }
+
+ public function getAlias()
+ {
+ return 'security';
+ }
+
+ /**
+ * Loads the web configuration.
+ *
+ * @param array $config An array of configuration settings
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ */
- $hierarchy[$id] = is_array($value) ? $value : preg_split('/\s*,\s*/', $value);
+ protected function createRoleHierarchy($config, ContainerBuilder $container)
+ {
+ if (!isset($config['role_hierarchy'])) {
+ return;
}
- $container->setParameter('security.role_hierarchy.roles', $hierarchy);
+ $container->setParameter('security.role_hierarchy.roles', $config['role_hierarchy']);
$container->remove('security.access.simple_role_voter');
$container->getDefinition('security.access.role_hierarchy_voter')->addTag('security.voter');
}
protected function createAuthorization($config, ContainerBuilder $container)
{
- $rules = array();
- if (isset($config['access_control'])) {
- $rules = $config['access_control'];
- }
-
- if (isset($rules['rule']) && is_array($rules['rule'])) {
- $rules = $rules['rule'];
+ if (!isset($config['access_control'])) {
+ return;
}
- foreach ($rules as $i => $access) {
- $roles = isset($access['role']) ? (is_array($access['role']) ? $access['role'] : preg_split('/\s*,\s*/', $access['role'])) : array();
- $channel = null;
- if (isset($access['requires_channel'])) {
- $channel = $access['requires_channel'];
- }
-
- // matcher
- $path = $host = $methods = $ip = null;
- if (isset($access['path'])) {
- $path = $access['path'];
- }
- if (isset($access['host'])) {
- $host = $access['host'];
- }
- if (count($tMethods = $this->normalizeConfig($access, 'method')) > 0) {
- $methods = $tMethods;
- }
- if (isset($access['ip'])) {
- $ip = $access['ip'];
- }
-
- $matchAttributes = array();
- $attributes = $this->normalizeConfig($access, 'attribute');
- foreach ($attributes as $key => $attribute) {
- if (isset($attribute['key'])) {
- $key = $attribute['key'];
- }
- $matchAttributes[$key] = $attribute['pattern'];
- }
- $matcher = $this->createRequestMatcher($container, $path, $host, $methods, $ip, $matchAttributes);
+ foreach ($config['access_control'] as $access) {
+ $matcher = $this->createRequestMatcher(
+ $container,
+ $access['path'],
+ $access['host'],
+ count($access['methods']) === 0 ? null : $access['methods'],
+ $access['ip'],
+ $access['attributes']
+ );
- $container->getDefinition('security.access_map')->addMethodCall('add', array($matcher, $roles, $channel));
+ $container->getDefinition('security.access_map')
+ ->addMethodCall('add', array($matcher, $access['roles'], $access['requires_channel']));
}
}
protected function createFirewalls($config, ContainerBuilder $container)
{
+ if (!isset($config['firewalls'])) {
+ return;
+ }
+
+ $firewalls = $config['firewalls'];
$providerIds = $this->createUserProviders($config, $container);
$this->createEncoders($config, $container);
- if (!$firewalls = $this->normalizeConfig($config, 'firewall')) {
- return;
- }
-
// make the ContextListener aware of the configured user providers
$definition = $container->getDefinition('security.context_listener');
$arguments = $definition->getArguments();
@@ -185,16 +179,8 @@ protected function createFirewalls($config, ContainerBuilder $container)
// load firewall map
$mapDef = $container->getDefinition('security.firewall.map');
- $names = $map = array();
+ $map = array();
foreach ($firewalls as $name => $firewall) {
- if (isset($firewall['name'])) {
- $name = $firewall['name'];
- }
- if (in_array($name, $names)) {
- throw new \RuntimeException(sprintf('The firewall name must be unique. Duplicate found: "%s"', $name));
- }
- $names[] = $name;
-
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $providerIds, $factories);
$contextId = 'security.firewall.map.context.'.$name;
@@ -220,7 +206,7 @@ protected function createFirewall(ContainerBuilder $container, $id, $firewall, $
}
// Security disabled?
- if (isset($firewall['security']) && !$firewall['security']) {
+ if (false === $firewall['security']) {
return array($matcher, array(), null);
}
@@ -228,9 +214,6 @@ protected function createFirewall(ContainerBuilder $container, $id, $firewall, $
if (isset($firewall['provider'])) {
$defaultProvider = $this->getUserProviderId($firewall['provider']);
} else {
- if (!$providerIds) {
- throw new \InvalidArgumentException('You must provide at least one authentication provider.');
- }
$defaultProvider = reset($providerIds);
}
@@ -242,7 +225,7 @@ protected function createFirewall(ContainerBuilder $container, $id, $firewall, $
$listeners[] = new Reference('security.channel_listener');
// Context serializer listener
- if (!isset($firewall['stateless']) || !$firewall['stateless']) {
+ if (false === $firewall['stateless']) {
$contextKey = $id;
if (isset($firewall['context'])) {
$contextKey = $firewall['context'];
@@ -252,44 +235,29 @@ protected function createFirewall(ContainerBuilder $container, $id, $firewall, $
}
// Logout listener
- if (array_key_exists('logout', $firewall)) {
+ if (isset($firewall['logout'])) {
$listenerId = 'security.logout_listener.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener'));
-
+ $listener->addArgument($firewall['logout']['path']);
+ $listener->addArgument($firewall['logout']['target']);
$listeners[] = new Reference($listenerId);
- if (!is_array($firewall['logout'])) {
- $firewall['logout'] = array();
- }
-
- if (isset($firewall['logout']['path'])) {
- $listener->setArgument(1, $firewall['logout']['path']);
- }
-
- if (isset($firewall['logout']['target'])) {
- $listener->setArgument(2, $firewall['logout']['target']);
- }
-
// add session logout handler
- $invalidateSession = true;
- if (isset($firewall['logout']['invalidate_session'])) {
- $invalidateSession = (Boolean) $firewall['logout']['invalidate_session'];
- }
- if (true === $invalidateSession && (!isset($firewall['stateless']) || !$firewall['stateless'])) {
+ if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
}
// add cookie logout handler
- if (count($cookies = $this->normalizeConfig($firewall['logout'], 'cookie')) > 0) {
+ if (count($firewall['logout']['delete_cookies']) > 0) {
$cookieHandlerId = 'security.logout.handler.cookie_clearing.'.$id;
$cookieHandler = $container->setDefinition($cookieHandlerId, new DefinitionDecorator('security.logout.handler.cookie_clearing'));
- $cookieHandler->addArgument($cookies);
+ $cookieHandler->addArgument($firewall['logout']['delete_cookies']);
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
}
// add custom handlers
- foreach ($this->normalizeConfig($firewall['logout'], 'handler') as $handlerId) {
+ foreach ($firewall['logout']['handlers'] as $handlerId) {
$listener->addMethodCall('addHandler', array(new Reference($handlerId)));
}
}
@@ -303,7 +271,7 @@ protected function createFirewall(ContainerBuilder $container, $id, $firewall, $
$listeners[] = new Reference('security.access_listener');
// Switch user listener
- if (array_key_exists('switch_user', $firewall)) {
+ if (isset($firewall['switch_user'])) {
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider));
}
@@ -340,13 +308,9 @@ protected function createAuthenticationListeners($container, $id, $firewall, $de
foreach ($this->listenerPositions as $position) {
foreach ($factories[$position] as $factory) {
- $key = $factory->getKey();
- $keybis = str_replace('-', '_', $key);
+ $key = str_replace('-', '_', $factory->getKey());
- if (array_key_exists($keybis, $firewall)) {
- $firewall[$key] = $firewall[$keybis];
- }
- if (array_key_exists($key, $firewall) && $firewall[$key] !== false) {
+ if (isset($firewall[$key])) {
$userProvider = isset($firewall[$key]['provider']) ? $this->getUserProviderId($firewall[$key]['provider']) : $defaultProvider;
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
@@ -359,7 +323,7 @@ protected function createAuthenticationListeners($container, $id, $firewall, $de
}
// Anonymous
- if (array_key_exists('anonymous', $firewall)) {
+ if (isset($firewall['anonymous'])) {
$listeners[] = new Reference('security.authentication.listener.anonymous');
$hasListeners = true;
}
@@ -371,66 +335,14 @@ protected function createAuthenticationListeners($container, $id, $firewall, $de
return array($listeners, $providers, $defaultEntryPoint);
}
- // Parses user providers and returns an array of their ids
- protected function createUserProviders($config, ContainerBuilder $container)
- {
- $providers = $this->normalizeConfig($config, 'provider');
- if (!$providers) {
- return array();
- }
-
- $providerIds = array();
- foreach ($providers as $name => $provider) {
- $id = $this->createUserDaoProvider($name, $provider, $container);
-
- if (in_array($id, $providerIds, true)) {
- throw new \RuntimeException(sprintf('Provider names must be unique. Duplicate entry for %s.', $id));
- }
-
- $providerIds[] = $id;
- }
-
- return $providerIds;
- }
-
- protected function createListenerFactories(ContainerBuilder $container, $config)
- {
- // load service templates
- $c = new ContainerBuilder();
- $parameterBag = $container->getParameterBag();
- $loader = new XmlFileLoader($c, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('security_factories.xml');
-
- // load user-created listener factories
- foreach ($this->normalizeConfig($config, 'factory', 'factories') as $factory) {
- $loader->load($parameterBag->resolveValue($factory));
- }
-
- $tags = $c->findTaggedServiceIds('security.listener.factory');
-
- $factories = array();
- foreach ($this->listenerPositions as $position) {
- $factories[$position] = array();
- }
-
- foreach (array_keys($tags) as $tag) {
- $factory = $c->get($tag);
-
- $factories[$factory->getPosition()][] = $factory;
- }
-
- return $factories;
- }
-
protected function createEncoders($config, ContainerBuilder $container)
{
- $encoders = $this->normalizeConfig($config, 'encoder');
- if (!$encoders) {
- return array();
+ if (!isset($config['encoders'])) {
+ return;
}
$encoderMap = array();
- foreach ($encoders as $class => $encoder) {
+ foreach ($config['encoders'] as $class => $encoder) {
$encoderMap = $this->createEncoder($encoderMap, $class, $encoder, $container);
}
@@ -442,21 +354,6 @@ protected function createEncoders($config, ContainerBuilder $container)
protected function createEncoder(array $encoderMap, $accountClass, $config, ContainerBuilder $container)
{
- if (is_array($config) && isset($config['class'])) {
- $accountClass = $config['class'];
- }
-
- if (empty($accountClass)) {
- throw new \RuntimeException('Each encoder needs an account class.');
- }
-
- // a minimal message digest, or plaintext encoder
- if (is_string($config)) {
- $config = array(
- 'algorithm' => $config,
- );
- }
-
// a custom encoder service
if (isset($config['id'])) {
$container
@@ -467,17 +364,12 @@ protected function createEncoder(array $encoderMap, $accountClass, $config, Cont
return $encoderMap;
}
- // a lazy loaded, message digest or plaintext encoder
- if (!isset($config['algorithm'])) {
- throw new \RuntimeException('"algorithm" must be defined.');
- }
-
// plaintext encoder
if ('plaintext' === $config['algorithm']) {
$arguments = array();
if (isset($config['ignore_case'])) {
- $arguments[0] = (Boolean) $config['ignore_case'];
+ $arguments[0] = $config['ignore_case'];
}
$encoderMap[$accountClass] = array(
@@ -493,7 +385,7 @@ protected function createEncoder(array $encoderMap, $accountClass, $config, Cont
// add optional arguments
if (isset($config['encode_as_base64'])) {
- $arguments[1] = (Boolean) $config['encode_as_base64'];
+ $arguments[1] = $config['encode_as_base64'];
} else {
$arguments[1] = false;
}
@@ -512,17 +404,23 @@ protected function createEncoder(array $encoderMap, $accountClass, $config, Cont
return $encoderMap;
}
- // Parses a tag and returns the id for the related user provider service
- protected function createUserDaoProvider($name, $provider, ContainerBuilder $container, $master = true)
+ // Parses user providers and returns an array of their ids
+ protected function createUserProviders($config, ContainerBuilder $container)
{
- if (isset($provider['name'])) {
- $name = $provider['name'];
+ $providerIds = array();
+ foreach ($config['providers'] as $name => $provider) {
+ $id = $this->createUserDaoProvider($name, $provider, $container);
+ $providerIds[] = $id;
}
- if (!$name) {
- throw new \RuntimeException('You must define a name for each user provider.');
- }
+ return $providerIds;
+ }
+ // Parses a tag and returns the id for the related user provider service
+ // FIXME: Replace register() calls in this method with DefinitionDecorator
+ // and move the actual definition to an xml file
+ protected function createUserDaoProvider($name, $provider, ContainerBuilder $container, $master = true)
+ {
$name = $this->getUserProviderId(strtolower($name));
// Existing DAO service provider
@@ -533,7 +431,7 @@ protected function createUserDaoProvider($name, $provider, ContainerBuilder $con
}
// Chain provider
- if (isset($provider['provider'])) {
+ if (count($provider['providers']) > 0) {
// FIXME
throw new \RuntimeException('Not implemented yet.');
}
@@ -546,8 +444,9 @@ protected function createUserDaoProvider($name, $provider, ContainerBuilder $con
->setArguments(array(
new Reference('security.user.entity_manager'),
$provider['entity']['class'],
- isset($provider['entity']['property']) ? $provider['entity']['property'] : null,
- ));
+ $provider['entity']['property'],
+ ))
+ ;
return $name;
}
@@ -560,7 +459,7 @@ protected function createUserDaoProvider($name, $provider, ContainerBuilder $con
->setArguments(array(
new Reference('security.user.document_manager'),
$provider['document']['class'],
- isset($provider['document']['property']) ? $provider['document']['property'] : null,
+ $provider['document']['property'],
));
return $name;
@@ -569,27 +468,8 @@ protected function createUserDaoProvider($name, $provider, ContainerBuilder $con
// In-memory DAO provider
$definition = $container->register($name, '%security.user.provider.in_memory.class%');
$definition->setPublic(false);
- foreach ($this->normalizeConfig($provider, 'user') as $username => $user) {
- if (isset($user['name'])) {
- $username = $user['name'];
- }
-
- if (!array_key_exists('password', $user)) {
- // if no password is provided explicitly, it means that
- // the user will be used with OpenID, X.509 certificates, ...
- // Let's generate a random password just to be sure this
- // won't be used accidentally with other authentication schemes.
- // If you want an empty password, just say so explicitly
- $user['password'] = uniqid();
- }
-
- if (!isset($user['roles'])) {
- $user['roles'] = array();
- } else {
- $user['roles'] = is_array($user['roles']) ? $user['roles'] : preg_split('/\s*,\s*/', $user['roles']);
- }
-
- $userId = $name.'_'.md5(serialize(array($username, $user['password'], $user['roles'])));
+ foreach ($provider['users'] as $username => $user) {
+ $userId = $name.'_'.md5(json_encode(array($username, $user['password'], $user['roles'])));
$container
->register($userId, 'Symfony\Component\Security\Core\User\User')
@@ -632,14 +512,8 @@ protected function createSwitchUserListener($container, $id, $config, $defaultPr
$listener = $container->setDefinition($switchUserListenerId, new DefinitionDecorator('security.authentication.switchuser_listener'));
$listener->setArgument(1, new Reference($userProvider));
$listener->setArgument(3, $id);
-
- if (isset($config['parameter'])) {
- $listener->setArgument(5, $config['parameter']);
- }
-
- if (isset($config['role'])) {
- $listener->setArgument(6, $config['role']);
- }
+ $listener->addArgument($config['parameter']);
+ $listener->addArgument($config['role']);
return $switchUserListenerId;
}
@@ -668,42 +542,35 @@ protected function createRequestMatcher($container, $path = null, $host = null,
return $this->requestMatchers[$id] = new Reference($id);
}
- protected function doAclLoad(array $config, ContainerBuilder $container)
+ protected function createListenerFactories(ContainerBuilder $container, $config)
{
- if (!$container->hasDefinition('security.acl')) {
- $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
- $loader->load('security_acl.xml');
+ if (null !== $this->factories) {
+ return $this->factories;
}
- if (isset($config['connection'])) {
- $container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
- }
+ // load service templates
+ $c = new ContainerBuilder();
+ $parameterBag = $container->getParameterBag();
+ $loader = new XmlFileLoader($c, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
+ $loader->load('security_factories.xml');
- if (isset($config['cache'])) {
- $container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
- } else {
- $container->remove('security.acl.cache.doctrine');
- $container->removeAlias('security.acl.cache.doctrine.cache_impl');
+ // load user-created listener factories
+ foreach ($config['factories'] as $factory) {
+ $loader->load($parameterBag->resolveValue($factory));
}
- }
- /**
- * Returns the base path for the XSD files.
- *
- * @return string The XSD base path
- */
- public function getXsdValidationBasePath()
- {
- return __DIR__.'/../Resources/config/schema';
- }
+ $tags = $c->findTaggedServiceIds('security.listener.factory');
- public function getNamespace()
- {
- return 'http://www.symfony-project.org/schema/dic/security';
- }
+ $factories = array();
+ foreach ($this->listenerPositions as $position) {
+ $factories[$position] = array();
+ }
- public function getAlias()
- {
- return 'security';
+ foreach (array_keys($tags) as $tag) {
+ $factory = $c->get($tag);
+ $factories[$factory->getPosition()][] = $factory;
+ }
+
+ return $this->factories = $factories;
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml
index 3245168813088..f36a6c461a7ea 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml
@@ -28,12 +28,8 @@
Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener
Symfony\Component\Security\Http\Firewall\SwitchUserListener
- ROLE_ALLOWED_TO_SWITCH
- _switch_user
Symfony\Component\Security\Http\Firewall\LogoutListener
- /logout
- /
Symfony\Component\Security\Http\Logout\SessionLogoutHandler
Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler
@@ -83,14 +79,12 @@
-
+
- %security.logout.path%
- %security.logout.target_path%
@@ -162,13 +156,11 @@
-
+
- %security.authentication.switchuser.parameter%
- %security.authentication.switchuser.role%
diff --git a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php
index 46436fb27d91c..b62d9b7557077 100644
--- a/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php
+++ b/src/Symfony/Bundle/SecurityBundle/SecurityBundle.php
@@ -30,20 +30,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new AddSecurityVotersPass());
$container->addCompilerPass(new AddAuthenticationProvidersPass());
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge.php
new file mode 100644
index 0000000000000..988640fb284dc
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge.php
@@ -0,0 +1,15 @@
+load('merge_import.php', $container);
+
+$container->loadFromExtension('security', 'config', array(
+ 'firewalls' => array(
+ 'main' => array(
+ 'form_login' => false,
+ 'http_basic' => null,
+ ),
+ ),
+ 'role_hierarchy' => array(
+ 'FOO' => array('MOO'),
+ )
+));
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge_import.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge_import.php
new file mode 100644
index 0000000000000..2b9be399d77c7
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/merge_import.php
@@ -0,0 +1,15 @@
+loadFromExtension('security', 'config', array(
+ 'firewalls' => array(
+ 'main' => array(
+ 'form_login' => array(
+ 'login_path' => '/login',
+ )
+ )
+ ),
+ 'role_hierarchy' => array(
+ 'FOO' => 'BAR',
+ 'ADMIN' => 'USER',
+ ),
+));
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access.xml
index c01acd61013eb..2ca9f5b9d0c7d 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/access.xml
@@ -6,12 +6,9 @@
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
-
-
-
-
-
-
-
+
+
+
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/hierarchy.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/hierarchy.xml
index 795105230cd04..4c8985a79157a 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/hierarchy.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/hierarchy.xml
@@ -6,10 +6,8 @@
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
-
- ROLE_USER
- ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH
- ROLE_USER,ROLE_ADMIN
-
+ ROLE_USER
+ ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH
+ ROLE_USER,ROLE_ADMIN
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge.xml
new file mode 100644
index 0000000000000..36f7b4de7208f
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge_import.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge_import.xml
new file mode 100644
index 0000000000000..806719ab5fa07
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/merge_import.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge.yml
new file mode 100644
index 0000000000000..a42fc99fab00c
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge.yml
@@ -0,0 +1,11 @@
+imports:
+ - { resource: merge_import.yml }
+
+security.config:
+ firewalls:
+ main:
+ form_login: false
+ http_basic: ~
+
+ role_hierarchy:
+ FOO: [MOO]
\ No newline at end of file
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge_import.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge_import.yml
new file mode 100644
index 0000000000000..497fb398c770c
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/merge_import.yml
@@ -0,0 +1,9 @@
+security.config:
+ firewalls:
+ main:
+ form_login:
+ login_path: /login
+
+ role_hierarchy:
+ FOO: BAR
+ ADMIN: USER
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
index 9d6d1390ee062..c412ce0e30d00 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
@@ -28,7 +28,7 @@ public function testCreate()
list($authProviderId,
$listenerId,
$entryPointId
- ) = $factory->create($container, 'foo', array('use_forward' => true, 'failure_path' => '/foo', 'success_handler' => 'foo'), 'user_provider', 'entry_point');
+ ) = $factory->create($container, 'foo', array('use_forward' => true, 'failure_path' => '/foo', 'success_handler' => 'foo', 'remember_me' => true), 'user_provider', 'entry_point');
// auth provider
$this->assertEquals('auth_provider', $authProviderId);
@@ -41,15 +41,8 @@ public function testCreate()
$this->assertEquals(array(
'index_3' => 'foo',
'index_4' => array(
- 'check_path' => '/login_check',
- 'login_path' => '/login',
'use_forward' => true,
- 'always_use_default_target_path' => false,
- 'default_target_path' => '/',
- 'target_path_parameter' => '_target_path',
- 'use_referer' => false,
'failure_path' => '/foo',
- 'failure_forward' => false,
),
'index_5' => new Reference('foo'),
), $definition->getArguments());
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
index d76f505d93952..73df0096914ea 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
@@ -36,10 +36,10 @@ public function testUserProviders()
$expectedProviders = array(
'security.authentication.provider.digest',
- 'security.authentication.provider.digest_0ff1b54f2a4b7f71b2b9d6604fcca4b8',
+ 'security.authentication.provider.digest_23374fce51fe846516ff85bfa9add8fe',
'security.authentication.provider.basic',
- 'security.authentication.provider.basic_b7f0cf21802ffc8b22cadbb255f07213',
- 'security.authentication.provider.basic_98e44377704554700e68c22094b51ca4',
+ 'security.authentication.provider.basic_745e8583f784c83c4b4208fd281001f3',
+ 'security.authentication.provider.basic_af4bcce7246fb064b8e219034043d88a',
'security.authentication.provider.doctrine',
'security.authentication.provider.service',
'security.authentication.provider.anonymous',
@@ -109,6 +109,16 @@ public function testAccess()
}
}
+ public function testMerge()
+ {
+ $container = $this->getContainer('merge');
+
+ $this->assertEquals(array(
+ 'FOO' => array('MOO'),
+ 'ADMIN' => array('USER'),
+ ), $container->getParameter('security.role_hierarchy.roles'));
+ }
+
protected function getContainer($file)
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Bundle/SwiftmailerBundle/SwiftmailerBundle.php b/src/Symfony/Bundle/SwiftmailerBundle/SwiftmailerBundle.php
index 7480863e96580..8b0a3a4a10148 100644
--- a/src/Symfony/Bundle/SwiftmailerBundle/SwiftmailerBundle.php
+++ b/src/Symfony/Bundle/SwiftmailerBundle/SwiftmailerBundle.php
@@ -20,19 +20,4 @@
*/
class SwiftmailerBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/TwigBundle/TwigBundle.php b/src/Symfony/Bundle/TwigBundle/TwigBundle.php
index dff10138a6da3..d27d85bcd2d67 100644
--- a/src/Symfony/Bundle/TwigBundle/TwigBundle.php
+++ b/src/Symfony/Bundle/TwigBundle/TwigBundle.php
@@ -28,20 +28,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new TwigEnvironmentPass());
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/WebProfilerBundle.php b/src/Symfony/Bundle/WebProfilerBundle/WebProfilerBundle.php
index 0a265a0004f7a..b3558f8ab3da0 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/WebProfilerBundle.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/WebProfilerBundle.php
@@ -20,19 +20,4 @@
*/
class WebProfilerBundle extends Bundle
{
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Bundle/ZendBundle/ZendBundle.php b/src/Symfony/Bundle/ZendBundle/ZendBundle.php
index e53ad48cb6476..c06f2636ab746 100644
--- a/src/Symfony/Bundle/ZendBundle/ZendBundle.php
+++ b/src/Symfony/Bundle/ZendBundle/ZendBundle.php
@@ -28,20 +28,4 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new ZendLoggerWriterPass());
}
-
- /**
- * {@inheritdoc}
- */
- public function getNamespace()
- {
- return __NAMESPACE__;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPath()
- {
- return __DIR__;
- }
}
diff --git a/src/Symfony/Component/CssSelector/Parser.php b/src/Symfony/Component/CssSelector/Parser.php
index 6861f80899b6a..4e80fc6098d4f 100644
--- a/src/Symfony/Component/CssSelector/Parser.php
+++ b/src/Symfony/Component/CssSelector/Parser.php
@@ -25,7 +25,16 @@
class Parser
{
/**
+ * Translate a CSS expression to its XPath equivalent.
+ * Optionally, a prefix can be added to the resulting XPath
+ * expression with the $prefix parameter.
+ *
* @throws SyntaxError When got None for xpath expression
+ *
+ * @param mixed $cssExpr The CSS expression.
+ * @param string $prefix An optional prefix for the XPath expression.
+ *
+ * @return string
*/
static public function cssToXpath($cssExpr, $prefix = 'descendant-or-self::')
{
@@ -62,7 +71,14 @@ static public function cssToXpath($cssExpr, $prefix = 'descendant-or-self::')
}
/**
+ * Parse an expression and return the Node object that represents
+ * the parsed expression.
+ *
* @throws \Exception When tokenizer throws it while parsing
+ *
+ * @param string $string The expression to parse
+ *
+ * @return Node\NodeInterface
*/
public function parse($string)
{
@@ -79,6 +95,14 @@ public function parse($string)
}
}
+ /**
+ * Parse a selector group contained in $stream and return
+ * the Node object that represents the expression.
+ *
+ * @param TokenStream $stream The stream to parse.
+ *
+ * @return Node\NodeInterface
+ */
protected function parseSelectorGroup($stream)
{
$result = array();
@@ -99,7 +123,14 @@ protected function parseSelectorGroup($stream)
}
/**
+ * Parse a selector contained in $stream and return the Node
+ * object that represents it.
+ *
* @throws SyntaxError When expected selector but got something else
+ *
+ * @param TokenStrem $stream The stream containing the selector.
+ *
+ * @return Node\NodeInterface
*/
protected function parseSelector($stream)
{
@@ -128,7 +159,14 @@ protected function parseSelector($stream)
}
/**
+ * Parse a simple selector (the current token) from $stream and return
+ * the resulting Node object.
+ *
* @throws SyntaxError When expected symbol but got something else
+ *
+ * @param TokenStream The stream containing the selector.
+ *
+ * @return Node\NodeInterface
*/
protected function parseSimpleSelector($stream)
{
@@ -228,7 +266,16 @@ protected function parseSimpleSelector($stream)
}
/**
+ * Parse an attribute from a selector contained in $stream and return
+ * the resulting AttribNode object.
+ *
* @throws SyntaxError When encountered unexpected selector
+ *
+ * @param Node\NodeInterface $selector The selector object whose attribute
+ * is to be parsed.
+ * @param TokenStream $strem The container token stream.
+ *
+ * @return Node\AttribNode
*/
protected function parseAttrib($selector, $stream)
{
diff --git a/src/Symfony/Component/CssSelector/Token.php b/src/Symfony/Component/CssSelector/Token.php
index 0dcb750167045..176617ac77850 100644
--- a/src/Symfony/Component/CssSelector/Token.php
+++ b/src/Symfony/Component/CssSelector/Token.php
@@ -25,6 +25,13 @@ class Token
protected $value;
protected $position;
+ /**
+ * Constructor.
+ *
+ * @param string $type The type of this token.
+ * @param mixed $value The value of this token.
+ * @param int $position The order of this token.
+ */
public function __construct($type, $value, $position)
{
$this->type = $type;
@@ -32,16 +39,33 @@ public function __construct($type, $value, $position)
$this->position = $position;
}
+ /**
+ * Get a string representation of this token.
+ *
+ * @return string
+ */
public function __toString()
{
return (string) $this->value;
}
+ /**
+ * Answer whether this token's type equals to $type.
+ *
+ * @param string $type The type to test against this token's one.
+ *
+ * @return bool
+ */
public function isType($type)
{
return $this->type == $type;
}
+ /**
+ * Get the position of this token.
+ *
+ * @return int
+ */
public function getPosition()
{
return $this->position;
diff --git a/src/Symfony/Component/CssSelector/TokenStream.php b/src/Symfony/Component/CssSelector/TokenStream.php
index 5e262530aedcd..c6e62f312d6fb 100644
--- a/src/Symfony/Component/CssSelector/TokenStream.php
+++ b/src/Symfony/Component/CssSelector/TokenStream.php
@@ -27,6 +27,12 @@ class TokenStream
protected $peeked;
protected $peeking;
+ /**
+ * Constructor.
+ *
+ * @param array $tokens The tokens that make the stream.
+ * @param mixed $source The source of the stream.
+ */
public function __construct($tokens, $source = null)
{
$this->used = array();
@@ -36,11 +42,23 @@ public function __construct($tokens, $source = null)
$this->peeking = false;
}
+ /**
+ * Get the tokens that have already been visited in this stream.
+ *
+ * @return array
+ */
public function getUsed()
{
return $this->used;
}
+ /**
+ * Get the next token in the stream or null if there is none.
+ * Note that if this stream was set to be peeking its behavior
+ * will be restored to not peeking after this operation.
+ *
+ * @return mixed
+ */
public function next()
{
if ($this->peeking) {
@@ -60,6 +78,16 @@ public function next()
return $next;
}
+ /**
+ * Peek for the next token in this stream. This means that the next token
+ * will be returned but it won't be considered as used (visited) until the
+ * next() method is invoked.
+ * If there are no remaining tokens null will be returned.
+ *
+ * @see next()
+ *
+ * @return mixed
+ */
public function peek()
{
if (!$this->peeking) {
diff --git a/src/Symfony/Component/CssSelector/Tokenizer.php b/src/Symfony/Component/CssSelector/Tokenizer.php
index 339eed25e4821..5980f5a9f3eea 100644
--- a/src/Symfony/Component/CssSelector/Tokenizer.php
+++ b/src/Symfony/Component/CssSelector/Tokenizer.php
@@ -21,6 +21,14 @@
*/
class Tokenizer
{
+ /**
+ * Take a CSS selector and return an array holding the Tokens
+ * it contains.
+ *
+ * @param string $s The selector to lex.
+ *
+ * @return array Token[]
+ */
public function tokenize($s)
{
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
@@ -95,7 +103,16 @@ public function tokenize($s)
}
/**
+ * Tokenize a quoted string (i.e. 'A string quoted with \' characters'),
+ * and return an array holding the unquoted string contained by $s and
+ * the new position from which tokenizing should take over.
+ *
* @throws SyntaxError When expected closing is not found
+ *
+ * @param string $s The selector string containing the quoted string.
+ * @param int $pos The starting position for the quoted string.
+ *
+ * @return array
*/
protected function tokenizeEscapedString($s, $pos)
{
@@ -125,7 +142,13 @@ protected function tokenizeEscapedString($s, $pos)
}
/**
+ * Unescape a string literal and return the unescaped string.
+ *
* @throws SyntaxError When invalid escape sequence is found
+ *
+ * @param string $literal The string literal to unescape.
+ *
+ * @return string
*/
protected function unescapeStringLiteral($literal)
{
@@ -143,7 +166,16 @@ protected function unescapeStringLiteral($literal)
}
/**
+ * Lex selector $s and return the an array holding the name of the symbol
+ * contained in it and the new position from which tokenizing should take
+ * over.
+ *
* @throws SyntaxError When Unexpected symbol is found
+ *
+ * @param string $s The selector string.
+ * @param int $pos The position in $s at which the symbol starts.
+ *
+ * @return array
*/
protected function tokenizeSymbol($s, $pos)
{
diff --git a/src/Symfony/Component/CssSelector/XPathExpr.php b/src/Symfony/Component/CssSelector/XPathExpr.php
index 52262e6efcf7c..cd32a8cc43b34 100644
--- a/src/Symfony/Component/CssSelector/XPathExpr.php
+++ b/src/Symfony/Component/CssSelector/XPathExpr.php
@@ -27,6 +27,15 @@ class XPathExpr
protected $condition;
protected $starPrefix;
+ /**
+ * Constructor.
+ *
+ * @param string $prefix Prefix for the XPath expression.
+ * @param string $path Actual path of the expression.
+ * @param string $element The element in the expression.
+ * @param string $condition A condition for the expression.
+ * @param bool $starPrefix Indicates whether to use a star prefix.
+ */
public function __construct($prefix = null, $path = null, $element = '*', $condition = null, $starPrefix = false)
{
$this->prefix = $prefix;
@@ -36,31 +45,61 @@ public function __construct($prefix = null, $path = null, $element = '*', $condi
$this->starPrefix = $starPrefix;
}
+ /**
+ * Get the prefix of this XPath expression.
+ *
+ * @return string
+ */
public function getPrefix()
{
return $this->prefix;
}
+ /**
+ * Get the path of this XPath expression.
+ *
+ * @return string
+ */
public function getPath()
{
return $this->path;
}
+ /**
+ * Answer whether this XPath expression has a star prefix.
+ *
+ * @return bool
+ */
public function hasStarPrefix()
{
return $this->starPrefix;
}
+ /**
+ * Get the element of this XPath expression.
+ *
+ * @return string
+ */
public function getElement()
{
return $this->element;
}
+ /**
+ * Get the condition of this XPath expression.
+ *
+ * @return string
+ */
public function getCondition()
{
return $this->condition;
}
+ /**
+ * Get a string representation for this XPath expression.
+ *
+ * @return string
+ */
public function __toString()
{
$path = '';
@@ -81,6 +120,12 @@ public function __toString()
return $path;
}
+ /**
+ * Add a condition to this XPath expression.
+ * Any pre-existant condition will be ANDed to it.
+ *
+ * @param string $condition The condition to add.
+ */
public function addCondition($condition)
{
if ($this->condition) {
@@ -90,6 +135,12 @@ public function addCondition($condition)
}
}
+ /**
+ * Add a prefix to this XPath expression.
+ * It will be prepended to any pre-existant prefixes.
+ *
+ * @param string $prefix The prefix to add.
+ */
public function addPrefix($prefix)
{
if ($this->prefix) {
@@ -99,6 +150,11 @@ public function addPrefix($prefix)
}
}
+ /**
+ * Add a condition to this XPath expression using the name of the element
+ * as the desired value.
+ * This method resets the element to '*'.
+ */
public function addNameTest()
{
if ($this->element == '*') {
@@ -110,6 +166,11 @@ public function addNameTest()
$this->element = '*';
}
+ /**
+ * Add a star prefix to this XPath expression.
+ * This method will prepend a '*' to the path and set the star prefix flag
+ * to true.
+ */
public function addStarPrefix()
{
/*
@@ -125,6 +186,14 @@ public function addStarPrefix()
$this->starPrefix = true;
}
+ /**
+ * Join this XPath expression with $other (another XPath expression) using
+ * $combiner to join them.
+ *
+ * @param string $combiner The combiner string.
+ * @param XPathExpr $other The other XPath expression to combine with
+ * this one.
+ */
public function join($combiner, $other)
{
$prefix = (string) $this;
@@ -143,6 +212,13 @@ public function join($combiner, $other)
$this->condition = $other->GetCondition();
}
+ /**
+ * Get an XPath literal for $s.
+ *
+ * @param mixed $s Can either be a Node\ElementNode or a string.
+ *
+ * @return string
+ */
static public function xpathLiteral($s)
{
if ($s instanceof Node\ElementNode) {
diff --git a/src/Symfony/Component/CssSelector/XPathExprOr.php b/src/Symfony/Component/CssSelector/XPathExprOr.php
index c5347ba1306e6..21aa5a95494a8 100644
--- a/src/Symfony/Component/CssSelector/XPathExprOr.php
+++ b/src/Symfony/Component/CssSelector/XPathExprOr.php
@@ -23,12 +23,23 @@
*/
class XPathExprOr extends XPathExpr
{
+ /**
+ * Constructor.
+ *
+ * @param array $items The items in the expression.
+ * @param string $prefix Optional prefix for the expression.
+ */
public function __construct($items, $prefix = null)
{
$this->items = $items;
$this->prefix = $prefix;
}
+ /**
+ * Get a string representation of this |'d expression.
+ *
+ * @return string
+ */
public function __toString()
{
$prefix = $this->prefix;
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php
index 4b93f9ac0f3c3..dc2654e77294c 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php
@@ -41,7 +41,7 @@ public function process(ContainerBuilder $container)
// non-synthetic, non-abstract service has class
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
- if ($definition->getFactoryService()) {
+ if ($definition->getFactoryClass() || $definition->getFactoryService()) {
throw new \RuntimeException(sprintf(
'Please add the class to service "%s" even if it is constructed '
.'by a factory since we might need to add method calls based on '
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
index a0cc8213f541f..d3961ca57432b 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
@@ -49,8 +49,9 @@ protected function resolveDefinition($id, DefinitionDecorator $definition)
$def->setClass($parentDef->getClass());
$def->setArguments($parentDef->getArguments());
$def->setMethodCalls($parentDef->getMethodCalls());
- $def->setFactoryService($parentDef->getFactoryService());
+ $def->setFactoryClass($parentDef->getFactoryClass());
$def->setFactoryMethod($parentDef->getFactoryMethod());
+ $def->setFactoryService($parentDef->getFactoryService());
$def->setConfigurator($parentDef->getConfigurator());
$def->setFile($parentDef->getFile());
$def->setPublic($parentDef->isPublic());
@@ -60,6 +61,9 @@ protected function resolveDefinition($id, DefinitionDecorator $definition)
if (isset($changes['class'])) {
$def->setClass($definition->getClass());
}
+ if (isset($changes['factory_class'])) {
+ $def->setFactoryClass($definition->getFactoryClass());
+ }
if (isset($changes['factory_method'])) {
$def->setFactoryMethod($definition->getFactoryMethod());
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInterfaceInjectorsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInterfaceInjectorsPass.php
index 1373665cd0391..2fecee1b6694e 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInterfaceInjectorsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInterfaceInjectorsPass.php
@@ -32,7 +32,7 @@ public function process(ContainerBuilder $container)
$loaded = false;
foreach ($container->getInterfaceInjectors() as $injector) {
- if (null !== $definition->getFactoryService()) {
+ if (null !== $definition->getFactoryClass() || null !== $definition->getFactoryService()) {
continue;
}
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/ArrayNode.php b/src/Symfony/Component/DependencyInjection/Configuration/ArrayNode.php
index 9a9fc165f8716..1b9cbdfdc1291 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/ArrayNode.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/ArrayNode.php
@@ -2,23 +2,117 @@
namespace Symfony\Component\DependencyInjection\Configuration;
-use Symfony\Component\DependencyInjection\Extension\Extension;
+use Symfony\Component\DependencyInjection\Configuration\Exception\InvalidConfigurationException;
+use Symfony\Component\DependencyInjection\Configuration\Exception\DuplicateKeyException;
use Symfony\Component\DependencyInjection\Configuration\Exception\InvalidTypeException;
+use Symfony\Component\DependencyInjection\Configuration\Exception\UnsetKeyException;
+use Symfony\Component\DependencyInjection\Extension\Extension;
+/**
+ * Represents an ARRAY node in the config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
class ArrayNode extends BaseNode implements PrototypeNodeInterface
{
- protected $normalizeTransformations;
+ protected $xmlRemappings;
protected $children;
protected $prototype;
protected $keyAttribute;
+ protected $allowFalse;
+ protected $allowNewKeys;
+ protected $addIfNotSet;
+ protected $minNumberOfElements;
+ protected $performDeepMerging;
- public function __construct($name, NodeInterface $parent = null, array $beforeTransformations = array(), array $afterTransformations = array(), array $normalizeTransformations = array(), $keyAttribute = null)
+ public function __construct($name, NodeInterface $parent = null)
{
- parent::__construct($name, $parent, $beforeTransformations, $afterTransformations);
+ parent::__construct($name, $parent);
$this->children = array();
- $this->normalizeTransformations = $normalizeTransformations;
- $this->keyAttribute = $keyAttribute;
+ $this->xmlRemappings = array();
+ $this->allowFalse = false;
+ $this->addIfNotSet = false;
+ $this->allowNewKeys = true;
+ $this->performDeepMerging = true;
+ $this->minNumberOfElements = 0;
+ }
+
+ /**
+ * Sets the xml remappings that should be performed.
+ *
+ * @param array $remappings an array of the form array(array(string, string))
+ * @return void
+ */
+ public function setXmlRemappings(array $remappings)
+ {
+ $this->xmlRemappings = $remappings;
+ }
+
+ /**
+ * Sets the minimum number of elements that a prototype based node must
+ * contain. By default this is zero, meaning no elements.
+ *
+ * @param integer $number
+ * @return void
+ */
+ public function setMinNumberOfElements($number)
+ {
+ $this->minNumberOfElements = $number;
+ }
+
+ /**
+ * The name of the attribute that should be used as key.
+ *
+ * This is only relevant for XML configurations, and only in combination
+ * with a prototype based node.
+ *
+ * @param string $attribute
+ * @return void
+ */
+ public function setKeyAttribute($attribute)
+ {
+ $this->keyAttribute = $attribute;
+ }
+
+ /**
+ * Sets whether to add default values for this array if it has not been
+ * defined in any of the configuration files.
+ *
+ * @param Boolean $boolean
+ * @return void
+ */
+ public function setAddIfNotSet($boolean)
+ {
+ $this->addIfNotSet = (Boolean) $boolean;
+ }
+
+ /**
+ * Sets whether false is allowed as value indicating that the array should
+ * be unset.
+ *
+ * @param Boolean $allow
+ * @return void
+ */
+ public function setAllowFalse($allow)
+ {
+ $this->allowFalse = (Boolean) $allow;
+ }
+
+ /**
+ * Sets whether new keys can be defined in subsequent configurations.
+ *
+ * @param Boolean $allow
+ * @return void
+ */
+ public function setAllowNewKeys($allow)
+ {
+ $this->allowNewKeys = (Boolean) $allow;
+ }
+
+ public function setPerformDeepMerging($boolean)
+ {
+ $this->performDeepMerging = (Boolean) $boolean;
}
public function setName($name)
@@ -26,10 +120,41 @@ public function setName($name)
$this->name = $name;
}
+ public function hasDefaultValue()
+ {
+ if (null !== $this->prototype) {
+ return true;
+ }
+
+ return $this->addIfNotSet;
+ }
+
+ public function getDefaultValue()
+ {
+ if (!$this->hasDefaultValue()) {
+ throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
+ }
+
+ if (null !== $this->prototype) {
+ return array();
+ }
+
+ $defaults = array();
+ foreach ($this->children as $name => $child) {
+ if (!$child->hasDefaultValue()) {
+ continue;
+ }
+
+ $defaults[$name] = $child->getDefaultValue();
+ }
+
+ return $defaults;
+ }
+
public function setPrototype(PrototypeNodeInterface $node)
{
if (count($this->children) > 0) {
- throw new \RuntimeException('An ARRAY node must either have concrete children, or a prototype node.');
+ throw new \RuntimeException($this->getPath().': An ARRAY node must either have concrete children, or a prototype node.');
}
$this->prototype = $node;
@@ -51,9 +176,65 @@ public function addChild(NodeInterface $node)
$this->children[$name] = $node;
}
+ protected function finalizeValue($value)
+ {
+ if (false === $value) {
+ throw new UnsetKeyException(sprintf(
+ 'Unsetting key for path "%s", value: %s',
+ $this->getPath(),
+ json_encode($value)
+ ));
+ }
+
+ if (null !== $this->prototype) {
+ foreach ($value as $k => $v) {
+ try {
+ $value[$k] = $this->prototype->finalize($v);
+ } catch (UnsetKeyException $unset) {
+ unset($value[$k]);
+ }
+ }
+
+ if (count($value) < $this->minNumberOfElements) {
+ throw new InvalidConfigurationException(sprintf(
+ 'You must define at least %d element(s) for path "%s".',
+ $this->minNumberOfElements,
+ $this->getPath()
+ ));
+ }
+
+ return $value;
+ }
+
+ foreach ($this->children as $name => $child) {
+ if (!array_key_exists($name, $value)) {
+ if ($child->isRequired()) {
+ throw new InvalidConfigurationException(sprintf(
+ 'The node at path "%s" must be configured.',
+ $this->getPath()
+ ));
+ }
+
+ if ($child->hasDefaultValue()) {
+ $value[$name] = $child->getDefaultValue();
+ }
+
+ continue;
+ }
+
+ try {
+ $value[$name] = $child->finalize($value[$name]);
+ } catch (UnsetKeyException $unset) {
+ unset($value[$name]);
+ }
+ }
+
+ return $value;
+ }
+
protected function validateType($value)
{
- if (!is_array($value)) {
+ if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
throw new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected array, but got %s',
$this->getPath(),
@@ -64,7 +245,11 @@ protected function validateType($value)
protected function normalizeValue($value)
{
- foreach ($this->normalizeTransformations as $transformation) {
+ if (false === $value) {
+ return $value;
+ }
+
+ foreach ($this->xmlRemappings as $transformation) {
list($singular, $plural) = $transformation;
if (!isset($value[$singular])) {
@@ -77,8 +262,24 @@ protected function normalizeValue($value)
if (null !== $this->prototype) {
$normalized = array();
foreach ($value as $k => $v) {
- if (null !== $this->keyAttribute && is_array($v) && isset($v[$this->keyAttribute])) {
- $k = $v[$this->keyAttribute];
+ if (null !== $this->keyAttribute && is_array($v)) {
+ if (!isset($v[$this->keyAttribute]) && is_int($k)) {
+ throw new InvalidConfigurationException(sprintf(
+ 'You must set a "%s" attribute for path "%s".',
+ $this->keyAttribute,
+ $this->getPath()
+ ));
+ } else if (isset($v[$this->keyAttribute])) {
+ $k = $v[$this->keyAttribute];
+ }
+
+ if (array_key_exists($k, $normalized)) {
+ throw new DuplicateKeyException(sprintf(
+ 'Duplicate key "%s" for path "%s".',
+ $k,
+ $this->getPath()
+ ));
+ }
}
$this->prototype->setName($k);
@@ -103,4 +304,50 @@ protected function normalizeValue($value)
return $normalized;
}
-}
+
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ if (false === $rightSide) {
+ // if this is still false after the last config has been merged the
+ // finalization pass will take care of removing this key entirely
+ return false;
+ }
+
+ if (false === $leftSide || !$this->performDeepMerging) {
+ return $rightSide;
+ }
+
+ foreach ($rightSide as $k => $v) {
+ // no conflict
+ if (!array_key_exists($k, $leftSide)) {
+ if (!$this->allowNewKeys) {
+ throw new InvalidConfigurationException(sprintf(
+ 'You are not allowed to define new elements for path "%s". '
+ .'Please define all elements for this path in one config file.',
+ $this->getPath()
+ ));
+ }
+
+ $leftSide[$k] = $v;
+ continue;
+ }
+
+ try {
+ if (null !== $this->prototype) {
+ $this->prototype->setName($k);
+ $leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
+ } else {
+ if (!isset($this->children[$k])) {
+ throw new \RuntimeException('merge() expects a normalized config array.');
+ }
+
+ $leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
+ }
+ } catch (UnsetKeyException $unset) {
+ unset($leftSide[$k]);
+ }
+ }
+
+ return $leftSide;
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/BaseNode.php b/src/Symfony/Component/DependencyInjection/Configuration/BaseNode.php
index 69f5847fbcd74..b2a78e9e910d5 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/BaseNode.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/BaseNode.php
@@ -2,15 +2,25 @@
namespace Symfony\Component\DependencyInjection\Configuration;
+use Symfony\Component\DependencyInjection\Configuration\Exception\Exception;
+use Symfony\Component\DependencyInjection\Configuration\Exception\ForbiddenOverwriteException;
+
+/**
+ * The base node class
+ *
+ * @author Johannes M. Schmitt
+ */
abstract class BaseNode implements NodeInterface
{
protected $name;
protected $parent;
- protected $beforeTransformations;
- protected $afterTransformations;
- protected $nodeFactory;
+ protected $normalizationClosures;
+ protected $finalValidationClosures;
+ protected $allowOverwrite;
+ protected $required;
+ protected $equivalentValues;
- public function __construct($name, NodeInterface $parent = null, $beforeTransformations = array(), $afterTransformations = array())
+ public function __construct($name, NodeInterface $parent = null)
{
if (false !== strpos($name, '.')) {
throw new \InvalidArgumentException('The name must not contain ".".');
@@ -18,8 +28,41 @@ public function __construct($name, NodeInterface $parent = null, $beforeTransfor
$this->name = $name;
$this->parent = $parent;
- $this->beforeTransformations = $beforeTransformations;
- $this->afterTransformations = $afterTransformations;
+ $this->normalizationClosures = array();
+ $this->finalValidationClosures = array();
+ $this->allowOverwrite = true;
+ $this->required = false;
+ $this->equivalentValues = array();
+ }
+
+ public function addEquivalentValue($originalValue, $equivalentValue)
+ {
+ $this->equivalentValues[] = array($originalValue, $equivalentValue);
+ }
+
+ public function setRequired($boolean)
+ {
+ $this->required = (Boolean) $boolean;
+ }
+
+ public function setAllowOverwrite($allow)
+ {
+ $this->allowOverwrite = (Boolean) $allow;
+ }
+
+ public function setNormalizationClosures(array $closures)
+ {
+ $this->normalizationClosures = $closures;
+ }
+
+ public function setFinalValidationClosures(array $closures)
+ {
+ $this->finalValidationClosures = $closures;
+ }
+
+ public function isRequired()
+ {
+ return $this->required;
}
public function getName()
@@ -38,22 +81,64 @@ public function getPath()
return $path;
}
+ public final function merge($leftSide, $rightSide)
+ {
+ if (!$this->allowOverwrite) {
+ throw new ForbiddenOverwriteException(sprintf(
+ 'Configuration path "%s" cannot be overwritten. You have to '
+ .'define all options for this path, and any of its sub-paths in '
+ .'one configuration section.',
+ $this->getPath()
+ ));
+ }
+
+ $this->validateType($leftSide);
+ $this->validateType($rightSide);
+
+ return $this->mergeValues($leftSide, $rightSide);
+ }
+
public final function normalize($value)
{
- // run before transformations
- foreach ($this->beforeTransformations as $transformation) {
- $value = $transformation($value);
+ // run custom normalization closures
+ foreach ($this->normalizationClosures as $closure) {
+ $value = $closure($value);
+ }
+
+ // replace value with their equivalent
+ foreach ($this->equivalentValues as $data) {
+ if ($data[0] === $value) {
+ $value = $data[1];
+ }
}
// validate type
$this->validateType($value);
// normalize value
- $value = $this->normalizeValue($value);
+ return $this->normalizeValue($value);
+ }
+
+ public final function finalize($value)
+ {
+ $this->validateType($value);
+
+ $value = $this->finalizeValue($value);
- // run after transformations
- foreach ($this->afterTransformations as $transformation) {
- $value = $transformation($value);
+ // Perform validation on the final value if a closure has been set.
+ // The closure is also allowed to return another value.
+ foreach ($this->finalValidationClosures as $closure) {
+ try {
+ $value = $closure($value);
+ } catch (Exception $correctEx) {
+ throw $correctEx;
+ } catch (\Exception $invalid) {
+ throw new InvalidConfigurationException(sprintf(
+ 'Invalid configuration for path "%s": %s',
+ $this->getPath(),
+ $invalid->getMessage()
+ ), $invalid->getCode(), $invalid);
+ }
}
return $value;
@@ -61,4 +146,6 @@ public final function normalize($value)
abstract protected function validateType($value);
abstract protected function normalizeValue($value);
+ abstract protected function mergeValues($leftSide, $rightSide);
+ abstract protected function finalizeValue($value);
}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/BooleanNode.php b/src/Symfony/Component/DependencyInjection/Configuration/BooleanNode.php
new file mode 100644
index 0000000000000..3960e0e756b5c
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/BooleanNode.php
@@ -0,0 +1,21 @@
+getPath(),
+ json_encode($value)
+ ));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php
index c8f2e0cbdd848..1e29a6ed72778 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php
@@ -2,6 +2,11 @@
namespace Symfony\Component\DependencyInjection\Configuration\Builder;
+/**
+ * This class builds an if expression.
+ *
+ * @author Johannes M. Schmitt
+ */
class ExprBuilder
{
public $parent;
@@ -13,8 +18,12 @@ public function __construct($parent)
$this->parent = $parent;
}
- public function ifTrue(\Closure $closure)
+ public function ifTrue(\Closure $closure = null)
{
+ if (null === $closure) {
+ $closure = function($v) { return true === $v; };
+ }
+
$this->ifPart = $closure;
return $this;
@@ -48,6 +57,31 @@ public function then(\Closure $closure)
return $this;
}
+ public function thenReplaceKeyWithAttribute($attribute)
+ {
+ $this->thenPart = function($v) {
+ $newValue = array();
+ foreach ($v as $k => $oldValue) {
+ if (is_array($oldValue) && isset($oldValue['id'])) {
+ $k = $oldValue['id'];
+ }
+
+ $newValue[$k] = $oldValue;
+ }
+
+ return $newValue;
+ };
+
+ return $this;
+ }
+
+ public function thenEmptyArray()
+ {
+ $this->thenPart = function($v) { return array(); };
+
+ return $this;
+ }
+
public function end()
{
if (null === $this->ifPart) {
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/MergeBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/MergeBuilder.php
new file mode 100644
index 0000000000000..5ac10001dbd44
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/MergeBuilder.php
@@ -0,0 +1,41 @@
+
+ */
+class MergeBuilder
+{
+ public $parent;
+ public $allowFalse;
+ public $allowOverwrite;
+
+ public function __construct($parent)
+ {
+ $this->parent = $parent;
+ $this->allowFalse = false;
+ $this->allowOverwrite = true;
+ }
+
+ public function allowUnset($allow = true)
+ {
+ $this->allowFalse = $allow;
+
+ return $this;
+ }
+
+ public function denyOverwrite($deny = true)
+ {
+ $this->allowOverwrite = !$deny;
+
+ return $this;
+ }
+
+ public function end()
+ {
+ return $this->parent;
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php
index 0c63068d71433..aa19de0e61139 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php
@@ -2,6 +2,11 @@
namespace Symfony\Component\DependencyInjection\Configuration\Builder;
+/**
+ * This class provides a fluent interface for building a config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
class NodeBuilder
{
/************
@@ -13,9 +18,20 @@ class NodeBuilder
public $parent;
public $children;
public $prototype;
- public $normalizeTransformations;
- public $beforeTransformations;
- public $afterTransformations;
+ public $normalization;
+ public $merge;
+ public $finalization;
+ public $defaultValue;
+ public $default;
+ public $addDefaults;
+ public $required;
+ public $atLeastOne;
+ public $allowNewKeys;
+ public $allowEmptyValue;
+ public $nullEquivalent;
+ public $trueEquivalent;
+ public $falseEquivalent;
+ public $performDeepMerging;
public function __construct($name, $type, $parent = null)
{
@@ -23,10 +39,28 @@ public function __construct($name, $type, $parent = null)
$this->type = $type;
$this->parent = $parent;
- $this->children =
- $this->beforeTransformations =
- $this->afterTransformations =
- $this->normalizeTransformations = array();
+ $this->default = false;
+ $this->required = false;
+ $this->addDefaults = false;
+ $this->allowNewKeys = true;
+ $this->atLeastOne = false;
+ $this->allowEmptyValue = true;
+ $this->children = array();
+ $this->performDeepMerging = true;
+
+ if ('boolean' === $type) {
+ $this->nullEquivalent = true;
+ } else if ('array' === $type) {
+ $this->nullEquivalent = array();
+ }
+
+ if ('array' === $type) {
+ $this->trueEquivalent = array();
+ } else {
+ $this->trueEquivalent = true;
+ }
+
+ $this->falseEquivalent = false;
}
/****************************
@@ -35,54 +69,178 @@ public function __construct($name, $type, $parent = null)
public function node($name, $type)
{
- $node = new NodeBuilder($name, $type, $this);
+ $node = new static($name, $type, $this);
return $this->children[$name] = $node;
}
- public function normalize($key, $plural = null)
+ public function arrayNode($name)
{
- if (null === $plural) {
- $plural = $key.'s';
- }
+ return $this->node($name, 'array');
+ }
+
+ public function scalarNode($name)
+ {
+ return $this->node($name, 'scalar');
+ }
+
+ public function booleanNode($name)
+ {
+ return $this->node($name, 'boolean');
+ }
- $this->normalizeTransformations[] = array($key, $plural);
+ public function defaultValue($value)
+ {
+ $this->default = true;
+ $this->defaultValue = $value;
return $this;
}
- public function key($name)
+ public function isRequired()
{
- $this->key = $name;
+ $this->required = true;
+
+ return $this;
+ }
+
+ public function containsNameValuePairsWithKeyAttribute($attribute)
+ {
+ $this->beforeNormalization()
+ ->ifArray()
+ ->thenReplaceKeyWithAttribute($attribute)
+ ;
+
+ $this->useAttributeAsKey($attribute);
return $this;
}
- public function before(\Closure $closure = null)
+ public function requiresAtLeastOneElement()
{
- if (null !== $closure) {
- $this->beforeTransformations[] = $closure;
+ $this->atLeastOne = true;
+
+ return $this;
+ }
+
+ public function treatNullLike($value)
+ {
+ $this->nullEquivalent = $value;
+
+ return $this;
+ }
+
+ public function treatTrueLike($value)
+ {
+ $this->trueEquivalent = $value;
+
+ return $this;
+ }
+
+ public function treatFalseLike($value)
+ {
+ $this->falseEquivalent = $value;
+
+ return $this;
+ }
+
+ public function defaultNull()
+ {
+ return $this->defaultValue(null);
+ }
+
+ public function defaultTrue()
+ {
+ return $this->defaultValue(true);
+ }
+
+ public function defaultFalse()
+ {
+ return $this->defaultValue(false);
+ }
- return $this;
+ public function addDefaultsIfNotSet()
+ {
+ $this->addDefaults = true;
+
+ return $this;
+ }
+
+ public function disallowNewKeysInSubsequentConfigs()
+ {
+ $this->allowNewKeys = false;
+
+ return $this;
+ }
+
+ protected function normalization()
+ {
+ if (null === $this->normalization) {
+ $this->normalization = new NormalizationBuilder($this);
}
- return $this->beforeTransformations[] = new ExprBuilder($this);
+ return $this->normalization;
}
- public function prototype($type)
+ public function beforeNormalization()
{
- return $this->prototype = new NodeBuilder(null, $type, $this);
+ return $this->normalization()->before();
}
- public function after(\Closure $closure = null)
+ public function fixXmlConfig($singular, $plural = null)
{
- if (null !== $closure) {
- $this->afterTransformations[] = $closure;
+ $this->normalization()->remap($singular, $plural);
- return $this;
+ return $this;
+ }
+
+ public function useAttributeAsKey($name)
+ {
+ $this->key = $name;
+
+ return $this;
+ }
+
+ protected function merge()
+ {
+ if (null === $this->merge) {
+ $this->merge = new MergeBuilder($this);
}
- return $this->afterTransformations[] = new ExprBuilder($this);
+ return $this->merge;
+ }
+
+ public function cannotBeOverwritten($deny = true)
+ {
+ $this->merge()->denyOverwrite($deny);
+
+ return $this;
+ }
+
+ public function cannotBeEmpty()
+ {
+ $this->allowEmptyValue = false;
+
+ return $this;
+ }
+
+ public function canBeUnset($allow = true)
+ {
+ $this->merge()->allowUnset($allow);
+
+ return $this;
+ }
+
+ public function prototype($type)
+ {
+ return $this->prototype = new static(null, $type, $this);
+ }
+
+ public function performNoDeepMerging()
+ {
+ $this->performDeepMerging = false;
+
+ return $this;
}
public function end()
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/NormalizationBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NormalizationBuilder.php
new file mode 100644
index 0000000000000..96e76cb586d57
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NormalizationBuilder.php
@@ -0,0 +1,48 @@
+
+ */
+class NormalizationBuilder
+{
+ public $parent;
+ public $before;
+ public $remappings;
+
+ public function __construct($parent)
+ {
+ $this->parent = $parent;
+
+ $this->keys = false;
+
+ $this->remappings =
+ $this->before =
+ $this->after = array();
+ }
+
+ public function remap($key, $plural = null)
+ {
+ if (null === $plural) {
+ $plural = $key.'s';
+ }
+
+ $this->remappings[] = array($key, $plural);
+
+ return $this;
+ }
+
+ public function before(\Closure $closure = null)
+ {
+ if (null !== $closure) {
+ $this->before[] = $closure;
+
+ return $this;
+ }
+
+ return $this->before[] = new ExprBuilder($this->parent);
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php
index 93f48bdf1936b..e24a23cb4dce5 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php
@@ -2,9 +2,18 @@
namespace Symfony\Component\DependencyInjection\Configuration\Builder;
+use Symfony\Component\DependencyInjection\Configuration\BaseNode;
+
+use Symfony\Component\DependencyInjection\Configuration\BooleanNode;
+
use Symfony\Component\DependencyInjection\Configuration\ArrayNode;
use Symfony\Component\DependencyInjection\Configuration\ScalarNode;
+/**
+ * This is the entry class for building your own config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
class TreeBuilder
{
protected $root;
@@ -32,9 +41,6 @@ public function buildTree()
protected function createConfigNode(NodeBuilder $node)
{
- $node->beforeTransformations = $this->buildExpressions($node->beforeTransformations);
- $node->afterTransformations = $this->buildExpressions($node->afterTransformations);
-
$method = 'create'.$node->type.'ConfigNode';
if (!method_exists($this, $method)) {
throw new \RuntimeException(sprintf('Unknown node type: "%s"', $node->type));
@@ -43,14 +49,77 @@ protected function createConfigNode(NodeBuilder $node)
return $this->$method($node);
}
+ protected function createBooleanConfigNode(NodeBuilder $node)
+ {
+ $configNode = new BooleanNode($node->name, $node->parent);
+ $this->configureScalarNode($configNode, $node);
+
+ return $configNode;
+ }
+
protected function createScalarConfigNode(NodeBuilder $node)
{
- return new ScalarNode($node->name, $node->parent, $node->beforeTransformations, $node->afterTransformations);
+ $configNode = new ScalarNode($node->name, $node->parent);
+ $this->configureScalarNode($configNode, $node);
+
+ return $configNode;
+ }
+
+ protected function configureScalarNode(ScalarNode $configNode, NodeBuilder $node)
+ {
+ if (null !== $node->normalization) {
+ $configNode->setNormalizationClosures(
+ $this->buildExpressions($node->normalization->before)
+ );
+ }
+
+ if (null !== $node->merge) {
+ $configNode->setAllowOverwrite($node->merge->allowOverwrite);
+ }
+
+ if (true === $node->default) {
+ $configNode->setDefaultValue($node->defaultValue);
+ }
+
+ if (false === $node->allowEmptyValue) {
+ $configNode->setAllowEmptyValue($node->allowEmptyValue);
+ }
+
+ $configNode->addEquivalentValue(null, $node->nullEquivalent);
+ $configNode->addEquivalentValue(true, $node->trueEquivalent);
+ $configNode->addEquivalentValue(false, $node->falseEquivalent);
}
protected function createArrayConfigNode(NodeBuilder $node)
{
- $configNode = new ArrayNode($node->name, $node->parent, $node->beforeTransformations, $node->afterTransformations, $node->normalizeTransformations, $node->key);
+ $configNode = new ArrayNode($node->name, $node->parent);
+ $configNode->setAddIfNotSet($node->addDefaults);
+ $configNode->setAllowNewKeys($node->allowNewKeys);
+ $configNode->addEquivalentValue(null, $node->nullEquivalent);
+ $configNode->addEquivalentValue(true, $node->trueEquivalent);
+ $configNode->addEquivalentValue(false, $node->falseEquivalent);
+ $configNode->setPerformDeepMerging($node->performDeepMerging);
+
+ if (null !== $node->key) {
+ $configNode->setKeyAttribute($node->key);
+ }
+
+ if (true === $node->atLeastOne) {
+ $configNode->setMinNumberOfElements(1);
+ }
+
+ if (null !== $node->normalization) {
+ $configNode->setNormalizationClosures(
+ $this->buildExpressions($node->normalization->before)
+ );
+
+ $configNode->setXmlRemappings($node->normalization->remappings);
+ }
+
+ if (null !== $node->merge) {
+ $configNode->setAllowOverwrite($node->merge->allowOverwrite);
+ $configNode->setAllowFalse($node->merge->allowFalse);
+ }
foreach ($node->children as $child) {
$child->parent = $configNode;
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/DuplicateKeyException.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/DuplicateKeyException.php
new file mode 100644
index 0000000000000..7da500ba5693f
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/DuplicateKeyException.php
@@ -0,0 +1,13 @@
+
+ */
+class DuplicateKeyException extends InvalidConfigurationException
+{
+}
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/Exception.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/Exception.php
index e5a464b27694d..c669089f472b4 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/Exception/Exception.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/Exception.php
@@ -2,6 +2,11 @@
namespace Symfony\Component\DependencyInjection\Configuration\Exception;
+/**
+ * Base exception for all configuration exceptions
+ *
+ * @author Johannes M. Schmitt
+ */
class Exception extends \RuntimeException
{
}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/ForbiddenOverwriteException.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/ForbiddenOverwriteException.php
new file mode 100644
index 0000000000000..0f7537747ec31
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/ForbiddenOverwriteException.php
@@ -0,0 +1,13 @@
+
+ */
+class ForbiddenOverwriteException extends InvalidConfigurationException
+{
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidConfigurationException.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidConfigurationException.php
new file mode 100644
index 0000000000000..71f3ffbd5282e
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidConfigurationException.php
@@ -0,0 +1,13 @@
+
+ */
+class InvalidConfigurationException extends Exception
+{
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidTypeException.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidTypeException.php
index 436c80fa80add..3cdbc52439c58 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidTypeException.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/InvalidTypeException.php
@@ -5,8 +5,8 @@
/**
* This exception is thrown if an invalid type is encountered.
*
- * @author johannes
+ * @author Johannes M. Schmitt
*/
-class InvalidTypeException extends Exception
+class InvalidTypeException extends InvalidConfigurationException
{
}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Exception/UnsetKeyException.php b/src/Symfony/Component/DependencyInjection/Configuration/Exception/UnsetKeyException.php
new file mode 100644
index 0000000000000..2388b134b42bb
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Exception/UnsetKeyException.php
@@ -0,0 +1,13 @@
+
+ */
+class UnsetKeyException extends Exception
+{
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/NodeInterface.php b/src/Symfony/Component/DependencyInjection/Configuration/NodeInterface.php
index a5e8611c637d1..70271946b46b5 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/NodeInterface.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/NodeInterface.php
@@ -2,9 +2,21 @@
namespace Symfony\Component\DependencyInjection\Configuration;
+/**
+ * Common Interface among all nodes.
+ *
+ * In most cases, it is better to inherit from BaseNode instead of implementing
+ * this interface yourself.
+ *
+ * @author Johannes M. Schmitt
+ */
interface NodeInterface
{
function getName();
function getPath();
+ function isRequired();
+ function hasDefaultValue();
+ function getDefaultValue();
function normalize($value);
+ function merge($leftSide, $rightSide);
}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Processor.php b/src/Symfony/Component/DependencyInjection/Configuration/Processor.php
new file mode 100644
index 0000000000000..cdabd29a030fe
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Configuration/Processor.php
@@ -0,0 +1,26 @@
+
+ */
+class Processor
+{
+ public function process(NodeInterface $configTree, array $configs)
+ {
+ $configs = Extension::normalizeKeys($configs);
+
+ $currentConfig = array();
+ foreach ($configs as $config) {
+ $config = $configTree->normalize($config);
+ $currentConfig = $configTree->merge($currentConfig, $config);
+ }
+
+ return $configTree->finalize($currentConfig);
+ }
+}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php b/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php
index cdcebe3dac6a7..fd871c3864590 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php
@@ -2,10 +2,41 @@
namespace Symfony\Component\DependencyInjection\Configuration;
+use Symfony\Component\DependencyInjection\Configuration\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\Configuration\Exception\InvalidTypeException;
+/**
+ * This node represents a scalar value in the config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
class ScalarNode extends BaseNode implements PrototypeNodeInterface
{
+ protected $defaultValueSet = false;
+ protected $defaultValue;
+ protected $allowEmptyValue = true;
+
+ public function setDefaultValue($value)
+ {
+ $this->defaultValueSet = true;
+ $this->defaultValue = $value;
+ }
+
+ public function hasDefaultValue()
+ {
+ return $this->defaultValueSet;
+ }
+
+ public function getDefaultValue()
+ {
+ return $this->defaultValue;
+ }
+
+ public function setAllowEmptyValue($boolean)
+ {
+ $this->allowEmptyValue = (Boolean) $boolean;
+ }
+
public function setName($name)
{
$this->name = $name;
@@ -14,7 +45,7 @@ public function setName($name)
protected function validateType($value)
{
if (!is_scalar($value)) {
- throw new \InvalidTypeException(sprintf(
+ throw new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected scalar, but got %s.',
$this->getPath(),
json_encode($value)
@@ -22,8 +53,26 @@ protected function validateType($value)
}
}
+ protected function finalizeValue($value)
+ {
+ if (!$this->allowEmptyValue && empty($value)) {
+ throw new InvalidConfigurationException(sprintf(
+ 'The path "%s" cannot contain an empty value, but got %s.',
+ $this->getPath(),
+ json_encode($value)
+ ));
+ }
+
+ return $value;
+ }
+
protected function normalizeValue($value)
{
return $value;
}
+
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ return $rightSide;
+ }
}
\ No newline at end of file
diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
index 8bf948e67b9e4..008ef416c269e 100644
--- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
@@ -695,10 +695,12 @@ protected function createService(Definition $definition, $id)
$arguments = $this->resolveServices($this->getParameterBag()->resolveValue($definition->getArguments()));
if (null !== $definition->getFactoryMethod()) {
- if (null !== $definition->getFactoryService()) {
+ if (null !== $definition->getFactoryClass()) {
+ $factory = $this->getParameterBag()->resolveValue($definition->getFactoryClass());
+ } elseif (null !== $definition->getFactoryService()) {
$factory = $this->get($this->getParameterBag()->resolveValue($definition->getFactoryService()));
} else {
- $factory = $this->getParameterBag()->resolveValue($definition->getClass());
+ throw new \RuntimeException('Cannot create service from factory method without a factory service or factory class.');
}
$service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php
index fa70eb6d14e55..e3d58cb6f2080 100644
--- a/src/Symfony/Component/DependencyInjection/Definition.php
+++ b/src/Symfony/Component/DependencyInjection/Definition.php
@@ -20,6 +20,7 @@ class Definition
{
protected $class;
protected $file;
+ protected $factoryClass;
protected $factoryMethod;
protected $factoryService;
protected $scope;
@@ -49,16 +50,41 @@ public function __construct($class = null, array $arguments = array())
$this->abstract = false;
}
+ /**
+ * Sets the name of the class that acts as a factory using the factory method,
+ * which will be invoked statically.
+ *
+ * @param string $factoryClass The factory class name
+ *
+ * @return Definition The current instance
+ */
+ public function setFactoryClass($factoryClass)
+ {
+ $this->factoryClass = $factoryClass;
+
+ return $this;
+ }
+
+ /**
+ * Gets the factory class.
+ *
+ * @return string The factory class name
+ */
+ public function getFactoryClass()
+ {
+ return $this->factoryClass;
+ }
+
/**
* Sets the factory method able to create an instance of this class.
*
- * @param string $method The method name
+ * @param string $factoryMethod The factory method name
*
* @return Definition The current instance
*/
- public function setFactoryMethod($method)
+ public function setFactoryMethod($factoryMethod)
{
- $this->factoryMethod = $method;
+ $this->factoryMethod = $factoryMethod;
return $this;
}
@@ -74,7 +100,7 @@ public function getFactoryMethod()
}
/**
- * Sets the name of the service that acts as a factory using the constructor method.
+ * Sets the name of the service that acts as a factory using the factory method.
*
* @param string $factoryService The factory service id
*
diff --git a/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php b/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php
index cde424c50bf18..e74a1bf7e319c 100644
--- a/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php
+++ b/src/Symfony/Component/DependencyInjection/DefinitionDecorator.php
@@ -37,11 +37,11 @@ public function setClass($class)
return parent::setClass($class);
}
- public function setFactoryService($service)
+ public function setFactoryClass($class)
{
- $this->changes['factory_service'] = true;
+ $this->changes['factory_class'] = true;
- return parent::setFactoryService($service);
+ return parent::setFactoryClass($class);
}
public function setFactoryMethod($method)
@@ -51,6 +51,13 @@ public function setFactoryMethod($method)
return parent::setFactoryMethod($method);
}
+ public function setFactoryService($service)
+ {
+ $this->changes['factory_service'] = true;
+
+ return parent::setFactoryService($service);
+ }
+
public function setConfigurator($callable)
{
$this->changes['configurator'] = true;
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 57e984f408bb9..7829b10b1a5fa 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -230,10 +230,12 @@ protected function addServiceInlinedDefinitions($id, $definition)
}
if (null !== $sDefinition->getFactoryMethod()) {
- if (null !== $sDefinition->getFactoryService()) {
+ if (null !== $sDefinition->getFactoryClass()) {
+ $code .= sprintf(" \$%s = call_user_func(array(%s, '%s')%s);\n", $name, $this->dumpValue($sDefinition->getFactoryClass()), $sDefinition->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
+ } elseif (null !== $sDefinition->getFactoryService()) {
$code .= sprintf(" \$%s = %s->%s(%s);\n", $name, $this->getServiceCall($sDefinition->getFactoryService()), $sDefinition->getFactoryMethod(), implode(', ', $arguments));
} else {
- $code .= sprintf(" \$%s = call_user_func(array(%s, '%s')%s);\n", $name, $class, $sDefinition->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
+ throw new \RuntimeException('Factory service or factory class must be defined in service definition for '.$id);
}
} elseif (false !== strpos($class, '$')) {
$code .= sprintf(" \$class = %s;\n \$%s = new \$class(%s);\n", $class, $name, implode(', ', $arguments));
@@ -294,10 +296,12 @@ protected function addServiceInstance($id, $definition)
}
if (null !== $definition->getFactoryMethod()) {
- if (null !== $definition->getFactoryService()) {
+ if (null !== $definition->getFactoryClass()) {
+ $code = sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
+ } elseif (null !== $definition->getFactoryService()) {
$code = sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
} else {
- $code = sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $class, $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
+ throw new \RuntimeException('Factory method requires a factory service or factory class in service definition for '.$id);
}
} elseif (false !== strpos($class, '$')) {
$code = sprintf(" \$class = %s;\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
@@ -404,8 +408,10 @@ protected function addService($id, $definition)
$return = '';
if ($definition->isSynthetic()) {
$return = sprintf('@throws \RuntimeException always since this service is expected to be injected dynamically');
- } else if ($class = $definition->getClass()) {
+ } elseif ($class = $definition->getClass()) {
$return = sprintf("@return %s A %s instance.", 0 === strpos($class, '%') ? 'Object' : $class, $class);
+ } elseif ($definition->getFactoryClass()) {
+ $return = sprintf('@return Object An instance returned by %s::%s().', $definition->getFactoryClass(), $definition->getFactoryMethod());
} elseif ($definition->getFactoryService()) {
$return = sprintf('@return Object An instance returned by %s::%s().', $definition->getFactoryService(), $definition->getFactoryMethod());
}
@@ -821,10 +827,12 @@ protected function dumpValue($value, $interpolate = true)
}
if (null !== $value->getFactoryMethod()) {
- if (null !== $value->getFactoryService()) {
+ if (null !== $value->getFactoryClass()) {
+ return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass()), $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
+ } elseif (null !== $value->getFactoryService()) {
return sprintf("%s->%s(%s)", $this->getServiceCall($value->getFactoryService()), $value->getFactoryMethod(), implode(', ', $arguments));
} else {
- return sprintf("call_user_func(array(%s, '%s')%s)", $class, $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
+ throw new \RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index ec0a10625ee25..ec39573f83b72 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -143,7 +143,7 @@ protected function parseDefinition($id, $service, $file)
$definition = new Definition();
}
- foreach (array('class', 'scope', 'public', 'factory-method', 'factory-service', 'synthetic', 'abstract') as $key) {
+ foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'abstract') as $key) {
if (isset($service[$key])) {
$method = 'set'.str_replace('-', '', $key);
$definition->$method((string) $service->getAttributeAsPhp($key));
diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
index 65def0455f834..926a274a00300 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
@@ -165,6 +165,10 @@ protected function parseDefinition($id, $service, $file)
$definition->setAbstract($service['abstract']);
}
+ if (isset($service['factory_class'])) {
+ $definition->setFactoryClass($service['factory_class']);
+ }
+
if (isset($service['factory_method'])) {
$definition->setFactoryMethod($service['factory_method']);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
index a6ccf726ee44f..35a8a684c9887 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
+++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
@@ -105,6 +105,7 @@
+
diff --git a/src/Symfony/Component/HttpFoundation/File/File.php b/src/Symfony/Component/HttpFoundation/File/File.php
index 8fd995d67351f..50464ea2a3759 100644
--- a/src/Symfony/Component/HttpFoundation/File/File.php
+++ b/src/Symfony/Component/HttpFoundation/File/File.php
@@ -605,7 +605,7 @@ public function getMimeType()
*/
public function size()
{
- if (false === ($size = filesize($this->getPath()))) {
+ if (false === ($size = @filesize($this->getPath()))) {
throw new FileException(sprintf('Could not read file size of %s', $this->getPath()));
}
@@ -623,7 +623,7 @@ protected function doMove($directory, $filename)
{
$newPath = $directory . DIRECTORY_SEPARATOR . $filename;
- if (!rename($this->getPath(), $newPath)) {
+ if (!@rename($this->getPath(), $newPath)) {
throw new FileException(sprintf('Could not move file %s to %s', $this->getPath(), $newPath));
}
diff --git a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php
index e214c00cd7238..17b5f75a73c71 100644
--- a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php
+++ b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php
@@ -25,6 +25,7 @@
abstract class Bundle extends ContainerAware implements BundleInterface
{
protected $name;
+ protected $reflected;
/**
* Boots the Bundle.
@@ -40,6 +41,34 @@ public function shutdown()
{
}
+ /**
+ * Gets the Bundle namespace.
+ *
+ * @return string The Bundle namespace
+ */
+ public function getNamespace()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+
+ return $this->reflected->getNamespaceName();
+ }
+
+ /**
+ * Gets the Bundle directory path.
+ *
+ * @return string The Bundle absolute path
+ */
+ public function getPath()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+
+ return strtr(dirname($this->reflected->getFileName()), '\\', '/');
+ }
+
/**
* Returns the bundle parent name.
*
@@ -67,18 +96,6 @@ final public function getName()
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
}
- /**
- * Gets the Bundle directory path.
- *
- * The path should always be returned as a Unix path (with /).
- *
- * @return string The Bundle absolute path
- */
- final public function getNormalizedPath()
- {
- return strtr($this->getPath(), '\\', '/');
- }
-
/**
* Finds and registers Dependency Injection Container extensions.
*
@@ -91,7 +108,7 @@ final public function getNormalizedPath()
*/
public function registerExtensions(ContainerBuilder $container)
{
- if (!$dir = realpath($this->getNormalizedPath().'/DependencyInjection')) {
+ if (!$dir = realpath($this->getPath().'/DependencyInjection')) {
return;
}
@@ -118,7 +135,7 @@ public function registerExtensions(ContainerBuilder $container)
*/
public function registerCommands(Application $application)
{
- if (!$dir = realpath($this->getNormalizedPath().'/Command')) {
+ if (!$dir = realpath($this->getPath().'/Command')) {
return;
}
diff --git a/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php b/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php
index fd55044e5ef5e..ba7f0ab6b647f 100644
--- a/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php
+++ b/src/Symfony/Component/HttpKernel/Bundle/BundleInterface.php
@@ -49,14 +49,6 @@ function getName();
*/
function getNamespace();
-
- /**
- * Gets the Bundle directory path.
- *
- * @return string The Bundle absolute path
- */
- function getPath();
-
/**
* Gets the Bundle directory path.
*
@@ -64,5 +56,5 @@ function getPath();
*
* @return string The Bundle absolute path
*/
- function getNormalizedPath();
+ function getPath();
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index c46d9bf1a150c..da64b790a76f0 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -237,7 +237,7 @@ public function locateResource($name, $dir = null, $first = true)
}
foreach ($this->getBundle($bundle, false) as $bundle) {
- if (file_exists($file = $bundle->getNormalizedPath().'/'.$path)) {
+ if (file_exists($file = $bundle->getPath().'/'.$path)) {
if ($first) {
return $file;
}
diff --git a/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
index 25d4cc1f5f77c..f82ecec163176 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
@@ -157,7 +157,10 @@ protected function exec($db, $query, array $args = array())
foreach ($args as $arg => $val) {
$stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
}
- $stmt->execute();
+ $success = $stmt->execute();
+ if (!$success) {
+ throw new \RuntimeException(sprintf('Error executing SQLite query "%s"', $query));
+ }
}
}
diff --git a/src/Symfony/Component/HttpKernel/bootstrap.php b/src/Symfony/Component/HttpKernel/bootstrap.php
index acdb86346579d..699e1f11a057d 100644
--- a/src/Symfony/Component/HttpKernel/bootstrap.php
+++ b/src/Symfony/Component/HttpKernel/bootstrap.php
@@ -113,7 +113,7 @@ public function getServiceIds()
$ids = array();
$r = new \ReflectionClass($this);
foreach ($r->getMethods() as $method) {
- if (preg_match('/^get(.+)Service$/', $name = $method->getName(), $match)) {
+ if (preg_match('/^get(.+)Service$/', $method->getName(), $match)) {
$ids[] = self::underscore($match[1]);
}
}
@@ -229,7 +229,6 @@ function getParent();
function getName();
function getNamespace();
function getPath();
- function getNormalizedPath();
}
}
namespace Symfony\Component\HttpKernel\Bundle
@@ -241,12 +240,27 @@ function getNormalizedPath();
abstract class Bundle extends ContainerAware implements BundleInterface
{
protected $name;
+ protected $reflected;
public function boot()
{
}
public function shutdown()
{
}
+ public function getNamespace()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+ return $this->reflected->getNamespaceName();
+ }
+ public function getPath()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+ return strtr(dirname($this->reflected->getFileName()), '\\', '/');
+ }
public function getParent()
{
return null;
@@ -260,13 +274,9 @@ final public function getName()
$pos = strrpos($name, '\\');
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
}
- final public function getNormalizedPath()
- {
- return strtr($this->getPath(), '\\', '/');
- }
public function registerExtensions(ContainerBuilder $container)
{
- if (!$dir = realpath($this->getNormalizedPath().'/DependencyInjection')) {
+ if (!$dir = realpath($this->getPath().'/DependencyInjection')) {
return;
}
$finder = new Finder();
@@ -279,7 +289,7 @@ public function registerExtensions(ContainerBuilder $container)
}
public function registerCommands(Application $application)
{
- if (!$dir = realpath($this->getNormalizedPath().'/Command')) {
+ if (!$dir = realpath($this->getPath().'/Command')) {
return;
}
$finder = new Finder();
@@ -577,7 +587,7 @@ public function locateResource($name, $dir = null, $first = true)
$files[] = $file;
}
foreach ($this->getBundle($bundle, false) as $bundle) {
- if (file_exists($file = $bundle->getNormalizedPath().'/'.$path)) {
+ if (file_exists($file = $bundle->getPath().'/'.$path)) {
if ($first) {
return $file;
}
diff --git a/src/Symfony/Component/HttpKernel/bootstrap_cache.php b/src/Symfony/Component/HttpKernel/bootstrap_cache.php
index 051f3bc25b43c..e1bbfc66aa100 100644
--- a/src/Symfony/Component/HttpKernel/bootstrap_cache.php
+++ b/src/Symfony/Component/HttpKernel/bootstrap_cache.php
@@ -151,7 +151,7 @@ public function locateResource($name, $dir = null, $first = true)
$files[] = $file;
}
foreach ($this->getBundle($bundle, false) as $bundle) {
- if (file_exists($file = $bundle->getNormalizedPath().'/'.$path)) {
+ if (file_exists($file = $bundle->getPath().'/'.$path)) {
if ($first) {
return $file;
}
diff --git a/tests/Symfony/Tests/Component/BrowserKit/ClientTest.php b/tests/Symfony/Tests/Component/BrowserKit/ClientTest.php
index 3d493f9d21ff2..42f45569dec2c 100644
--- a/tests/Symfony/Tests/Component/BrowserKit/ClientTest.php
+++ b/tests/Symfony/Tests/Component/BrowserKit/ClientTest.php
@@ -102,9 +102,6 @@ public function testGetResponse()
$this->assertEquals('foo', $client->getResponse()->getContent(), '->getCrawler() returns the Response of the last request');
}
- /**
- * @covers Symfony\Component\BrowserKit\Client::getContent
- */
public function testGetContent()
{
$json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}';
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Compiler/CheckDefinitionValidityPassTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Compiler/CheckDefinitionValidityPassTest.php
new file mode 100644
index 0000000000000..73d46bbc3853f
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Compiler/CheckDefinitionValidityPassTest.php
@@ -0,0 +1,61 @@
+register('a')->setSynthetic(true)->setPublic(false);
+
+ $this->process($container);
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testProcessDetectsSyntheticPrototypeDefinitions()
+ {
+ $container = new ContainerBuilder();
+ $container->register('a')->setSynthetic(true)->setScope(ContainerInterface::SCOPE_PROTOTYPE);
+
+ $this->process($container);
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testProcessDetectsNonSyntheticNonAbstractDefinitionWithoutClass()
+ {
+ $container = new ContainerBuilder();
+ $container->register('a')->setSynthetic(false)->setAbstract(false);
+
+ $this->process($container);
+ }
+
+ public function testProcess()
+ {
+ $container = new ContainerBuilder();
+ $container->register('a', 'class');
+ $container->register('b', 'class')->setSynthetic(true)->setPublic(true);
+ $container->register('c', 'class')->setAbstract(true);
+ $container->register('d', 'class')->setSynthetic(true);
+
+ $this->process($container);
+ }
+
+ protected function process(ContainerBuilder $container)
+ {
+ $pass = new CheckDefinitionValidityPass();
+ $pass->process($container);
+ }
+}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Configuration/ArrayNodeTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/ArrayNodeTest.php
new file mode 100644
index 0000000000000..da3155493e241
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/ArrayNodeTest.php
@@ -0,0 +1,17 @@
+normalize(false);
+ }
+}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Configuration/FinalizationTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/FinalizationTest.php
new file mode 100644
index 0000000000000..ab3f5af12babe
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/FinalizationTest.php
@@ -0,0 +1,59 @@
+root('config', 'array')
+ ->node('level1', 'array')
+ ->canBeUnset()
+ ->node('level2', 'array')
+ ->canBeUnset()
+ ->node('somevalue', 'scalar')->end()
+ ->node('anothervalue', 'scalar')->end()
+ ->end()
+ ->node('level1_scalar', 'scalar')->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'level1' => array(
+ 'level2' => array(
+ 'somevalue' => 'foo',
+ 'anothervalue' => 'bar',
+ ),
+ 'level1_scalar' => 'foo',
+ ),
+ );
+
+ $b = array(
+ 'level1' => array(
+ 'level2' => false,
+ ),
+ );
+
+ $this->assertEquals(array(
+ 'level1' => array(
+ 'level1_scalar' => 'foo',
+ ),
+ ), $this->process($tree, array($a, $b)));
+ }
+
+ protected function process(NodeInterface $tree, array $configs)
+ {
+ $processor = new Processor();
+
+ return $processor->process($tree, $configs);
+ }
+}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Configuration/MergeTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/MergeTest.php
new file mode 100644
index 0000000000000..0fab77cc11286
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/MergeTest.php
@@ -0,0 +1,148 @@
+root('root', 'array')
+ ->node('foo', 'scalar')
+ ->merge()
+ ->denyOverwrite()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'foo' => 'bar',
+ );
+
+ $b = array(
+ 'foo' => 'moo',
+ );
+
+ $tree->merge($a, $b);
+ }
+
+ public function testUnsetKey()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->node('unsettable', 'array')
+ ->merge()->allowUnset()->end()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->end()
+ ->node('unsetted', 'array')
+ ->merge()->allowUnset()->end()
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'foo' => 'bar',
+ 'unsettable' => array(
+ 'foo' => 'a',
+ 'bar' => 'b',
+ ),
+ 'unsetted' => false,
+ );
+
+ $b = array(
+ 'foo' => 'moo',
+ 'bar' => 'b',
+ 'unsettable' => false,
+ 'unsetted' => array('a', 'b'),
+ );
+
+ $this->assertEquals(array(
+ 'foo' => 'moo',
+ 'bar' => 'b',
+ 'unsettable' => false,
+ 'unsetted' => array('a', 'b'),
+ ), $tree->merge($a, $b));
+ }
+
+ /**
+ * @expectedException Symfony\Component\DependencyInjection\Configuration\Exception\InvalidConfigurationException
+ */
+ public function testDoesNotAllowNewKeysInSubsequentConfigs()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('config', 'array')
+ ->node('test', 'array')
+ ->disallowNewKeysInSubsequentConfigs()
+ ->useAttributeAsKey('key')
+ ->prototype('array')
+ ->node('value', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree();
+
+ $a = array(
+ 'test' => array(
+ 'a' => array('value' => 'foo')
+ )
+ );
+
+ $b = array(
+ 'test' => array(
+ 'b' => array('value' => 'foo')
+ )
+ );
+
+ $tree->merge($a, $b);
+ }
+
+ public function testPerformsNoDeepMerging()
+ {
+ $tb = new TreeBuilder();
+
+ $tree = $tb
+ ->root('config', 'array')
+ ->node('no_deep_merging', 'array')
+ ->performNoDeepMerging()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'no_deep_merging' => array(
+ 'foo' => 'a',
+ 'bar' => 'b',
+ ),
+ );
+
+ $b = array(
+ 'no_deep_merging' => array(
+ 'c' => 'd',
+ )
+ );
+
+ $this->assertEquals(array(
+ 'no_deep_merging' => array(
+ 'c' => 'd',
+ )
+ ), $tree->merge($a, $b));
+ }
+}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Configuration/NormalizationTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/NormalizationTest.php
index 4afbdb9eeeb86..9254700eb63ff 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/Configuration/NormalizationTest.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/NormalizationTest.php
@@ -15,11 +15,11 @@ public function testNormalizeEncoders($denormalized)
$tb = new TreeBuilder();
$tree = $tb
->root('root_name', 'array')
- ->normalize('encoder')
+ ->fixXmlConfig('encoder')
->node('encoders', 'array')
- ->key('class')
+ ->useAttributeAsKey('class')
->prototype('array')
- ->before()->ifString()->then(function($v) { return array('algorithm' => $v); })->end()
+ ->beforeNormalization()->ifString()->then(function($v) { return array('algorithm' => $v); })->end()
->node('algorithm', 'scalar')->end()
->end()
->end()
@@ -87,7 +87,7 @@ public function testAnonymousKeysArray($denormalized)
$tree = $tb
->root('root', 'array')
->node('logout', 'array')
- ->normalize('handler')
+ ->fixXmlConfig('handler')
->node('handlers', 'array')
->prototype('scalar')->end()
->end()
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/ContainerBuilderTest.php b/tests/Symfony/Tests/Component/DependencyInjection/ContainerBuilderTest.php
index b9d68f072e889..4a14e40664364 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/ContainerBuilderTest.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/ContainerBuilderTest.php
@@ -247,7 +247,7 @@ public function testCreateServiceFactoryMethod()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
- $builder->register('foo1', 'FooClass')->setFactoryMethod('getInstance')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar')));
+ $builder->register('foo1', 'FooClass')->setFactoryClass('FooClass')->setFactoryMethod('getInstance')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar')));
$builder->setParameter('value', 'bar');
$this->assertTrue($builder->get('foo1')->called, '->createService() calls the factory method to create the service instance');
$this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', $builder->get('bar')), $builder->get('foo1')->arguments, '->createService() passes the arguments to the factory method');
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/DefinitionDecoratorTest.php b/tests/Symfony/Tests/Component/DependencyInjection/DefinitionDecoratorTest.php
index ff80fba5d83b8..6c74adfe4a42d 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/DefinitionDecoratorTest.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/DefinitionDecoratorTest.php
@@ -34,8 +34,9 @@ public function getPropertyTests()
{
return array(
array('class', 'class'),
- array('factoryService', 'factory_service'),
+ array('factoryClass', 'factory_class'),
array('factoryMethod', 'factory_method'),
+ array('factoryService', 'factory_service'),
array('configurator', 'configurator'),
array('file', 'file'),
);
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/DefinitionTest.php b/tests/Symfony/Tests/Component/DependencyInjection/DefinitionTest.php
index 41ded4f06bc35..5a6097dcd3156 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/DefinitionTest.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/DefinitionTest.php
@@ -27,13 +27,18 @@ public function testConstructor()
$this->assertEquals(array('foo'), $def->getArguments(), '__construct() takes an optional array of arguments as its second argument');
}
- /**
- * @covers Symfony\Component\DependencyInjection\Definition::setFactoryMethod
- * @covers Symfony\Component\DependencyInjection\Definition::getFactoryMethod
- */
- public function testSetGetConstructor()
+ public function testSetGetFactoryClass()
+ {
+ $def = new Definition('stdClass');
+ $this->assertNull($def->getFactoryClass());
+ $this->assertSame($def, $def->setFactoryClass('stdClass2'), "->setFactoryClass() implements a fluent interface.");
+ $this->assertEquals('stdClass2', $def->getFactoryClass(), "->getFactoryClass() returns current class to construct this service.");
+ }
+
+ public function testSetGetFactoryMethod()
{
$def = new Definition('stdClass');
+ $this->assertNull($def->getFactoryMethod());
$this->assertSame($def, $def->setFactoryMethod('foo'), '->setFactoryMethod() implements a fluent interface');
$this->assertEquals('foo', $def->getFactoryMethod(), '->getFactoryMethod() returns the factory method name');
}
@@ -42,8 +47,8 @@ public function testSetGetFactoryService()
{
$def = new Definition('stdClass');
$this->assertNull($def->getFactoryService());
- $this->assertSame($def, $def->setFactoryService('stdClass2'), "->setFactoryService() implements a fluent interface.");
- $this->assertEquals('stdClass2', $def->getFactoryService(), "->getFactoryService() returns current service to construct this service.");
+ $this->assertSame($def, $def->setFactoryService('foo.bar'), "->setFactoryService() implements a fluent interface.");
+ $this->assertEquals('foo.bar', $def->getFactoryService(), "->getFactoryService() returns current service to construct this service.");
}
/**
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php
index 46c9dbb90932f..03e4c9db92829 100644
--- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php
@@ -12,6 +12,7 @@
register('foo', 'FooClass')->
addTag('foo', array('foo' => 'foo'))->
addTag('foo', array('bar' => 'bar'))->
+ setFactoryClass('FooClass')->
setFactoryMethod('getInstance')->
setArguments(array('foo', new Reference('foo.baz'), array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, new Reference('service_container')))->
setScope('prototype')->
@@ -27,6 +28,7 @@
;
$container->
register('foo.baz', '%baz_class%')->
+ setFactoryClass('%baz_class%')->
setFactoryMethod('getInstance')->
setConfigurator(array('%baz_class%', 'configureStatic1'))
;
diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/interfaces1.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/interfaces1.php
index c3efeb9f47207..27503a351c674 100755
--- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/interfaces1.php
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/interfaces1.php
@@ -12,12 +12,14 @@
return $container;
-class FooClass
-{
- public $bar;
-
- public function setBar($bar)
+if (!class_exists('FooClass')) {
+ class FooClass
{
- $this->bar = $bar;
+ public $bar;
+
+ public function setBar($bar)
+ {
+ $this->bar = $bar;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/File/FileTest.php b/tests/Symfony/Tests/Component/HttpFoundation/File/FileTest.php
index 15048f7c3dd84..7f5e41a7be800 100644
--- a/tests/Symfony/Tests/Component/HttpFoundation/File/FileTest.php
+++ b/tests/Symfony/Tests/Component/HttpFoundation/File/FileTest.php
@@ -28,10 +28,16 @@ public function testGetPathReturnsAbsolutePath()
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.gif', $this->file->getPath());
}
+ public function test__toString()
+ {
+ $this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.gif', (string) $this->file);
+ }
+
public function testGetWebPathReturnsPathRelativeToDocumentRoot()
{
File::setDocumentRoot(__DIR__);
+ $this->assertEquals(__DIR__, File::getDocumentRoot());
$this->assertEquals('/Fixtures/test.gif', $this->file->getWebPath());
}
@@ -42,11 +48,24 @@ public function testGetWebPathReturnsEmptyPathIfOutsideDocumentRoot()
$this->assertEquals('', $this->file->getWebPath());
}
+ public function testSetDocumentRootThrowsLogicExceptionWhenNotExists()
+ {
+ $this->setExpectedException('LogicException');
+
+ File::setDocumentRoot(__DIR__.'/Fixtures/not_here');
+ }
+
public function testGetNameReturnsNameWithExtension()
{
$this->assertEquals('test.gif', $this->file->getName());
}
+ public function testGetExtensionReturnsEmptyString()
+ {
+ $file = new File(__DIR__.'/Fixtures/test');
+ $this->assertEquals('', $file->getExtension());
+ }
+
public function testGetExtensionReturnsExtensionWithDot()
{
$this->assertEquals('.gif', $this->file->getExtension());
@@ -66,6 +85,13 @@ public function testGetMimeTypeUsesMimeTypeGuessers()
$this->assertEquals('image/gif', $this->file->getMimeType());
}
+ public function testGetDefaultExtensionWithoutGuesser()
+ {
+ $file = new File(__DIR__.'/Fixtures/directory/.empty');
+
+ $this->assertEquals('.empty', $file->getDefaultExtension());
+ }
+
public function testGetDefaultExtensionIsBasedOnMimeType()
{
$file = new File(__DIR__.'/Fixtures/test');
@@ -76,11 +102,33 @@ public function testGetDefaultExtensionIsBasedOnMimeType()
$this->assertEquals('.gif', $file->getDefaultExtension());
}
+ public function testConstructWhenFileNotExists()
+ {
+ $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
+
+ new File(__DIR__.'/Fixtures/not_here');
+ }
+
public function testSizeReturnsFileSize()
{
$this->assertEquals(filesize($this->file->getPath()), $this->file->size());
}
+ public function testSizeFailing()
+ {
+ $dir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'directory';
+ $path = $dir.DIRECTORY_SEPARATOR.'test.copy.gif';
+ @unlink($path);
+ copy(__DIR__.'/Fixtures/test.gif', $path);
+
+ $file = new File($path);
+ @unlink($path);
+
+ $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileException');
+ $file->size($path);
+
+ }
+
public function testMove()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
@@ -121,6 +169,27 @@ public function testMoveWithNewName()
@unlink($targetPath);
}
+ public function testMoveFailing()
+ {
+ $path = __DIR__.'/Fixtures/test.copy.gif';
+ $targetPath = '/thisfolderwontexist';
+ @unlink($path);
+ @unlink($targetPath);
+ copy(__DIR__.'/Fixtures/test.gif', $path);
+
+ $file = new File($path);
+
+ $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileException');
+ $file->move($targetPath);
+
+ $this->assertFileExists($path);
+ $this->assertFileNotExists($path.$targetPath.'test.gif');
+ $this->assertEquals($path, $file->getPath());
+
+ @unlink($path);
+ @unlink($targetPath);
+ }
+
public function testRename()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
diff --git a/tests/Symfony/Tests/Component/HttpKernel/Bundle/BundleTest.php b/tests/Symfony/Tests/Component/HttpKernel/Bundle/BundleTest.php
deleted file mode 100644
index b3bf6fed30e6f..0000000000000
--- a/tests/Symfony/Tests/Component/HttpKernel/Bundle/BundleTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Tests\Component\HttpKernel\Bundle;
-
-class BundleTest extends \PHPUnit_Framework_TestCase
-{
- public function testGetNormalizedPathReturnsANormalizedPath()
- {
- $bundle = $this
- ->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')
- ->setMethods(array('getPath'))
- ->disableOriginalConstructor()
- ->getMockForAbstractClass()
- ;
-
- $bundle
- ->expects($this->once())
- ->method('getPath')
- ->will($this->returnValue('path\\to\\foo\\bar'))
- ;
-
- $this->assertEquals('path/to/foo/bar', $bundle->getNormalizedPath());
- }
-}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerAggregateTest.php b/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerAggregateTest.php
new file mode 100644
index 0000000000000..4b75a4717392f
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerAggregateTest.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpKernel\CacheWarmer;
+
+use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
+use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
+use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer;
+
+class CacheWarmerAggregateTest extends \PHPUnit_Framework_TestCase
+{
+ protected static $cacheDir;
+
+ public static function setUpBeforeClass()
+ {
+ self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf2_cache_warmer_dir');
+ }
+
+ public function testInjectWarmersUsingConstructor()
+ {
+ $warmer = $this->getCacheWarmerMock();
+ $warmer
+ ->expects($this->once())
+ ->method('warmUp');
+ $aggregate = new CacheWarmerAggregate(array($warmer));
+ $aggregate->warmUp(self::$cacheDir);
+ }
+
+ public function testInjectWarmersUsingAdd()
+ {
+ $warmer = $this->getCacheWarmerMock();
+ $warmer
+ ->expects($this->once())
+ ->method('warmUp');
+ $aggregate = new CacheWarmerAggregate();
+ $aggregate->add($warmer);
+ $aggregate->warmUp(self::$cacheDir);
+ }
+
+ public function testInjectWarmersUsingSetWarmers()
+ {
+ $warmer = $this->getCacheWarmerMock();
+ $warmer
+ ->expects($this->once())
+ ->method('warmUp');
+ $aggregate = new CacheWarmerAggregate();
+ $aggregate->setWarmers(array($warmer));
+ $aggregate->warmUp(self::$cacheDir);
+ }
+
+ public function testWarmupDoesCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsEnabled()
+ {
+ $warmer = $this->getCacheWarmerMock();
+ $warmer
+ ->expects($this->never())
+ ->method('isOptional');
+ $warmer
+ ->expects($this->once())
+ ->method('warmUp');
+
+ $aggregate = new CacheWarmerAggregate(array($warmer));
+ $aggregate->enableOptionalWarmers();
+ $aggregate->warmUp(self::$cacheDir);
+ }
+
+ public function testWarmupDoesNotCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsNotEnabled()
+ {
+ $warmer = $this->getCacheWarmerMock();
+ $warmer
+ ->expects($this->once())
+ ->method('isOptional')
+ ->will($this->returnValue(true));
+ $warmer
+ ->expects($this->never())
+ ->method('warmUp');
+
+ $aggregate = new CacheWarmerAggregate(array($warmer));
+ $aggregate->warmUp(self::$cacheDir);
+ }
+
+ protected function getCacheWarmerMock()
+ {
+ $warmer = $this->getMockBuilder('Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ return $warmer;
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerTest.php b/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerTest.php
new file mode 100644
index 0000000000000..063a114978da0
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpKernel/CacheWarmer/CacheWarmerTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpKernel\CacheWarmer;
+
+use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
+use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer;
+
+class CacheWarmerTest extends \PHPUnit_Framework_TestCase
+{
+ protected static $cacheFile;
+
+ public static function setUpBeforeClass()
+ {
+ self::$cacheFile = tempnam(sys_get_temp_dir(), 'sf2_cache_warmer_dir');
+ }
+
+ public static function tearDownAfterClass()
+ {
+ @unlink(self::$cacheFile);
+ }
+
+ public function testWriteCacheFileCreatesTheFile()
+ {
+ $warmer = new TestCacheWarmer(self::$cacheFile);
+ $warmer->warmUp(dirname(self::$cacheFile));
+
+ $this->assertTrue(file_exists(self::$cacheFile));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testWriteNonWritableCacheFileThrowsARuntimeException()
+ {
+ $nonWritableFile = '/this/file/is/very/probably/not/writable';
+ $warmer = new TestCacheWarmer($nonWritableFile);
+ $warmer->warmUp(dirname($nonWritableFile));
+ }
+}
+
+class TestCacheWarmer extends CacheWarmer
+{
+ protected $file;
+
+ public function __construct($file)
+ {
+ $this->file = $file;
+ }
+
+ public function warmUp($cacheDir)
+ {
+ $this->writeCacheFile($this->file, 'content');
+ }
+
+ public function isOptional()
+ {
+ return false;
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php b/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
index 5695f5a6fdbaf..a97eb74aeb926 100644
--- a/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
+++ b/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
@@ -255,7 +255,7 @@ protected function getBundle($dir = null, $parent = null, $className = null, $bu
{
$bundle = $this
->getMockBuilder('Symfony\Tests\Component\HttpKernel\BundleForTest')
- ->setMethods(array('getNormalizedPath', 'getParent', 'getName'))
+ ->setMethods(array('getPath', 'getParent', 'getName'))
->disableOriginalConstructor()
;
@@ -273,7 +273,7 @@ protected function getBundle($dir = null, $parent = null, $className = null, $bu
$bundle
->expects($this->any())
- ->method('getNormalizedPath')
+ ->method('getPath')
->will($this->returnValue(strtr($dir, '\\', '/')))
;