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/DoctrineAbstractBundle/Common/DataFixtures/Loader.php b/src/Symfony/Bundle/DoctrineAbstractBundle/Common/DataFixtures/Loader.php
new file mode 100644
index 0000000000000..1e7c2f754b2f5
--- /dev/null
+++ b/src/Symfony/Bundle/DoctrineAbstractBundle/Common/DataFixtures/Loader.php
@@ -0,0 +1,27 @@
+container = $container;
+ }
+
+ public function addFixture(FixtureInterface $fixture)
+ {
+ if ($fixture instanceof ContainerAwareInterface) {
+ $fixture->setContainer($this->container);
+ }
+
+ parent::addFixture($fixture);
+ }
+}
diff --git a/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/ContainerAwareFixture.php b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/ContainerAwareFixture.php
new file mode 100644
index 0000000000000..51a873cd56dac
--- /dev/null
+++ b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/ContainerAwareFixture.php
@@ -0,0 +1,21 @@
+container = $container;
+ }
+
+ public function load($manager)
+ {
+ }
+}
diff --git a/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/DataFixtures/LoaderTest.php b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/DataFixtures/LoaderTest.php
new file mode 100644
index 0000000000000..8bef32a6e230c
--- /dev/null
+++ b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/Common/DataFixtures/LoaderTest.php
@@ -0,0 +1,21 @@
+getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+ $loader = new Loader($container);
+ $fixture = new ContainerAwareFixture();
+
+ $loader->addFixture($fixture);
+
+ $this->assertSame($container, $fixture->container);
+ }
+}
diff --git a/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/TestCase.php b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/TestCase.php
new file mode 100644
index 0000000000000..17326b6d5a876
--- /dev/null
+++ b/src/Symfony/Bundle/DoctrineAbstractBundle/Tests/TestCase.php
@@ -0,0 +1,13 @@
+markTestSkipped('Doctrine Data Fixtures is not available.');
+ }
+ }
+}
diff --git a/src/Symfony/Bundle/DoctrineBundle/Command/LoadDataFixturesDoctrineCommand.php b/src/Symfony/Bundle/DoctrineBundle/Command/LoadDataFixturesDoctrineCommand.php
index f0557b34eff04..3a369bbd61ef7 100644
--- a/src/Symfony/Bundle/DoctrineBundle/Command/LoadDataFixturesDoctrineCommand.php
+++ b/src/Symfony/Bundle/DoctrineBundle/Command/LoadDataFixturesDoctrineCommand.php
@@ -18,8 +18,11 @@
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Finder\Finder;
use Symfony\Bundle\FrameworkBundle\Util\Filesystem;
+use Symfony\Bundle\DoctrineAbstractBundle\Common\DataFixtures\Loader as DataFixturesLoader;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
+use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
+use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Internal\CommitOrderCalculator;
use Doctrine\ORM\Mapping\ClassMetadata;
@@ -72,15 +75,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}
- $loader = new \Doctrine\Common\DataFixtures\Loader();
+ $loader = new DataFixturesLoader($this->container);
foreach ($paths as $path) {
if (is_dir($path)) {
$loader->loadFromDirectory($path);
}
}
$fixtures = $loader->getFixtures();
- $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($em);
- $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($em, $purger);
+ $purger = new ORMPurger($em);
+ $executor = new ORMExecutor($em, $purger);
$executor->setLogger(function($message) use ($output) {
$output->writeln(sprintf(' > %s', $message));
});
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/Command/LoadDataFixturesDoctrineODMCommand.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Command/LoadDataFixturesDoctrineODMCommand.php
index 51609ab4d3771..bcaf9e0d85a16 100644
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Command/LoadDataFixturesDoctrineODMCommand.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Command/LoadDataFixturesDoctrineODMCommand.php
@@ -18,8 +18,11 @@
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Finder\Finder;
use Symfony\Bundle\FrameworkBundle\Util\Filesystem;
+use Symfony\Bundle\DoctrineAbstractBundle\Common\DataFixtures\Loader as DataFixturesLoader;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
+use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor;
+use Doctrine\Common\DataFixtures\Purger\MongoDBPurger;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Internal\CommitOrderCalculator;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
@@ -72,15 +75,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}
- $paths = array_filter($paths, 'is_dir');
-
- $loader = new \Doctrine\Common\DataFixtures\Loader();
+ $loader = new DataFixturesLoader($this->container);
foreach ($paths as $path) {
- $loader->loadFromDirectory($path);
+ if (is_dir($path)) {
+ $loader->loadFromDirectory($path);
+ }
}
$fixtures = $loader->getFixtures();
- $purger = new \Doctrine\Common\DataFixtures\Purger\MongoDBPurger($dm);
- $executor = new \Doctrine\Common\DataFixtures\Executor\MongoDBExecutor($dm, $purger);
+ $purger = new MongoDBPurger($dm);
+ $executor = new MongoDBExecutor($dm, $purger);
$executor->setLogger(function($message) use ($output) {
$output->writeln(sprintf(' > %s', $message));
});
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/DoctrineMongoDBBundle/Tests/Validator/Constraints/UniqueValidatorTest.php b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/Validator/Constraints/UniqueValidatorTest.php
index 4af23affe6d8c..f3e0d6fae7e1c 100755
--- a/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/Validator/Constraints/UniqueValidatorTest.php
+++ b/src/Symfony/Bundle/DoctrineMongoDBBundle/Tests/Validator/Constraints/UniqueValidatorTest.php
@@ -5,10 +5,11 @@
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ODM\MongoDB\DocumentRepository;
use Symfony\Bundle\DoctrineMongoDBBundle\Tests\Fixtures\Validator\Document;
+use Symfony\Bundle\DoctrineMongoDBBundle\Tests\TestCase;
use Symfony\Bundle\DoctrineMongoDBBundle\Validator\Constraints\Unique;
use Symfony\Bundle\DoctrineMongoDBBundle\Validator\Constraints\UniqueValidator;
-class UniqueValidatorTest extends \PHPUnit_Framework_TestCase
+class UniqueValidatorTest extends TestCase
{
private $dm;
private $repository;
@@ -18,6 +19,7 @@ class UniqueValidatorTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
+ parent::setUp();
$this->classMetadata = $this->getClassMetadata();
$this->repository = $this->getDocumentRepository();
$this->dm = $this->getDocumentManager($this->classMetadata, $this->repository);
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/Command/InitBundleCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/InitBundleCommand.php
index deb6a1639befb..500eb99eda21c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/InitBundleCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/InitBundleCommand.php
@@ -71,16 +71,18 @@ protected function execute(InputInterface $input, OutputInterface $output)
// user specified bundle name?
$bundle = $input->getArgument('bundleName');
- if ('' === $bundle) {
+ if (!$bundle) {
$bundle = strtr($namespace, array('\\' => ''));
- } elseif (!preg_match('/Bundle$/', $bundle)) {
+ }
+
+ if (!preg_match('/Bundle$/', $bundle)) {
throw new \InvalidArgumentException('The bundle name must end with Bundle.');
}
$dir = $input->getArgument('dir');
// add trailing / if necessary
- $dir = '/' === substr($dir, -1, 1) ? $dir : $dir . '/';
+ $dir = '/' === substr($dir, -1, 1) ? $dir : $dir.'/';
$targetDir = $dir.strtr($namespace, '\\', '/');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
index 118bbfaeb6696..806bd1835ef37 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
@@ -34,9 +34,11 @@ public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
- parent::__construct('Symfony', Kernel::VERSION.' - '.$kernel->getName());
+ parent::__construct('Symfony', Kernel::VERSION.' - '.$kernel->getName().'/'.$kernel->getEnvironment().($kernel->isDebug() ? '/debug' : ''));
$this->definition->addOption(new InputOption('--shell', '-s', InputOption::VALUE_NONE, 'Launch the shell.'));
+ $this->definition->addOption(new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'));
+ $this->definition->addOption(new InputOption('--debug', '-d', InputOption::VALUE_NONE, 'Whether to run in debug mode.'));
$this->kernel->boot();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
index cb094a3d6d37c..0f95d187a1a31 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php
@@ -47,7 +47,7 @@ public function redirectAction($route, $permanent = false)
$code = $permanent ? 301 : 302;
$attributes = $this->container->get('request')->attributes->all();
- unset($attributes['_route'], $attributes['route']);
+ unset($attributes['_route'], $attributes['route'], $attributes['permanent'] );
$response = $this->container->get('response');
$response->setRedirect($this->container->get('router')->generate($route, $attributes), $code);
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
new file mode 100644
index 0000000000000..066d1f3c829a9
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -0,0 +1,222 @@
+
+ */
+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('exception_controller')->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()
+ ->scalarNode('type')->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..d6121b0fc00dd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -11,150 +11,122 @@
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['exception_controller'])) {
+ $container->setParameter('exception_listener.controller', $config['exception_controller']);
}
- 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['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);
}
- if (isset($config['router'])) {
- $this->registerRouterConfiguration($config, $container);
+ if (isset($config['test']) && $config['test']) {
+ $loader->load('test.xml');
+ $config['session']['storage_id'] = 'array';
}
- if (isset($config['profiler'])) {
- $this->registerProfilerConfiguration($config, $container);
+ if (isset($config['csrf_protection'])) {
+ $this->registerCsrfProtectionConfiguration($config['csrf_protection'], $container);
}
- if (isset($config['validation']['enabled'])) {
- $this->registerValidationConfiguration($config, $container);
+ if (isset($config['esi'])) {
+ $this->registerEsiConfiguration($config['esi'], $loader);
}
- if (array_key_exists('templating', $config)) {
- $this->registerTemplatingConfiguration($config, $container);
+ if (isset($config['profiler'])) {
+ $this->registerProfilerConfiguration($config['profiler'], $container, $loader);
}
- if (array_key_exists('test', $config)) {
- $this->registerTestConfiguration($config, $container);
+ if (isset($config['router'])) {
+ $this->registerRouterConfiguration($config['router'], $container, $loader);
}
- if (array_key_exists('session', $config)) {
- $this->registerSessionConfiguration($config, $container);
+ if (isset($config['session'])) {
+ $this->registerSessionConfiguration($config['session'], $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['templating'])) {
+ $this->registerTemplatingConfiguration($config['templating'], $container, $loader);
}
- if (isset($config['cache-warmer'])) {
- $config['cache_warmer'] = $config['cache-warmer'];
+ if (isset($config['translator'])) {
+ $this->registerTranslatorConfiguration($config['translator'], $container);
}
- $warmer = isset($config['cache_warmer']) ? $config['cache_warmer'] : !$container->getParameter('kernel.debug');
- $container->setParameter('kernel.cache_warmup', $warmer);
+ if (isset($config['validation'])) {
+ $this->registerValidationConfiguration($config['validation'], $container, $loader);
+ }
$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\ParameterBag',
@@ -178,236 +150,119 @@ 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['type'])) {
+ $container->setParameter('router.options.resource_type', $config['type']);
}
- if (isset($config['auto-start'])) {
- $config['auto_start'] = $config['auto-start'];
+ if (isset($config['cache_warmer']) && $config['cache_warmer']) {
+ $container->getDefinition('router.cache_warmer')->addTag('kernel.cache_warmer');
+ $container->setAlias('router', 'router.cached');
}
+ $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 +271,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 +293,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']) && $config['loaders']) {
+ $loaders = array_map(function($loader) { return new Reference($loader); }, $config['loaders']);
+
+ // Use a delegation 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/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml
index 65ff4e29b029c..c75ca9aa9df1a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml
@@ -22,6 +22,7 @@
Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer
%kernel.name%%kernel.environment%UrlMatcher
%kernel.name%%kernel.environment%UrlGenerator
+
@@ -71,6 +72,7 @@
%router.options.matcher_base_class%
%router.options.matcher_dumper_class%
%router.options.matcher.cache_class%
+ %router.options.resource_type%
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..4a635a758e83a 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,51 @@
-
-
+
+
+
-
-
+
-
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -46,14 +63,9 @@
+
-
-
-
-
-
-
@@ -64,11 +76,14 @@
-
-
+
+
+
+
+
@@ -83,21 +98,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/Resources/translations/validators.es.xliff b/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.es.xliff
new file mode 100644
index 0000000000000..96e2fc6063498
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.es.xliff
@@ -0,0 +1,131 @@
+
+
+
+
+
+ This value should be false
+ Este valor debería ser falso
+
+
+ This value should be true
+ Este valor debería ser verdadero
+
+
+ This value should be of type {{ type }}
+ Este valor debería ser de tipo {{ type }}
+
+
+ This value should be blank
+ Este valor debería estar vacío
+
+
+ This value should be one of the given choices
+ Seleccione este valor entre las opciones mostradas
+
+
+ You should select at least {{ limit }} choices
+ Debería seleccionar al menos {{ limit }} opciones
+
+
+ You should select at most {{ limit }} choices
+ Debería seleccionar como máximo {{ limit }} opciones
+
+
+ The fields {{ fields }} were not expected
+ No se esperaban los campos {{ fields }}
+
+
+ The fields {{ fields }} are missing
+ Faltan los campos {{ fields }}
+
+
+ This value is not a valid date
+ Este valor no es una fecha válida
+
+
+ This value is not a valid datetime
+ Este valor no es una fecha y hora válidas
+
+
+ This value is not a valid email address
+ Este valor no es una dirección de email válida
+
+
+ The file could not be found
+ No se pudo encontrar el archivo
+
+
+ The file is not readable
+ No se puede leer el archivo
+
+
+ The file is too large ({{ size }}). Allowed maximum size is {{ limit }}
+ El archivo es demasiado grande ({{ size }}). El tamaño máximo permitido es {{ limit }}
+
+
+ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}
+ El tipo mime del archivo no es válido ({{ type }}). Los tipos mime válidos son {{ types }}
+
+
+ This value should be {{ limit }} or less
+ Este valor debería ser {{ limit }} o menos
+
+
+ This value is too long. It should have {{ limit }} characters or less
+ Este valor es demasiado largo. Debería tener {{ limit }} caracteres o menos
+
+
+ This value should be {{ limit }} or more
+ Este valor debería ser {{ limit }} o más
+
+
+ This value is too short. It should have {{ limit }} characters or more
+ Este valor es demasiado corto. Debería tener {{ limit }} caracteres o más
+
+
+ This value should not be blank
+ Este valor no debería estar vacío
+
+
+ This value should not be null
+ Este valor no debería ser null
+
+
+ This value should be null
+ Este valor debería ser null
+
+
+ This value is not valid
+ Este valor no es válido
+
+
+ This value is not a valid time
+ Este valor no es una hora válida
+
+
+ This value is not a valid URL
+ Este valor no es una URL válida
+
+
+ This value should be instance of class {{ class }}
+ Este valor debería ser una instancia de la clase {{ class }}
+
+
+ This field group should not contain extra fields
+ Este grupo de campos no debería contener campos adicionales
+
+
+ The uploaded file was too large. Please try to upload a smaller file
+ El archivo subido es demasiado grande. Por favor, suba un archivo más pequeño
+
+
+ The CSRF token is invalid
+ El token CSRF no es válido
+
+
+ The two values should be equal
+ Los dos valores deberían ser iguales
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.ja_JP.xliff b/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.ja_JP.xliff
new file mode 100644
index 0000000000000..cabba0c0d2f69
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.ja_JP.xliff
@@ -0,0 +1,131 @@
+
+
+
+
+
+ This value should be false
+ 値はfalseでなければなりません
+
+
+ This value should be true
+ 値はtrueでなければなりません
+
+
+ This value should be of type {{ type }}
+ 値の型は{{ type }}でなければなりません
+
+
+ This value should be blank
+ 値は空でなければなりません
+
+
+ This value should be one of the given choices
+ 値は指定された選択肢のうちの1つでなければなりません
+
+
+ You should select at least {{ limit }} choices
+ {{ limit }}個以上選択してください
+
+
+ You should select at most {{ limit }} choices
+ {{ limit }}個以内で選択してください
+
+
+ The fields {{ fields }} were not expected
+ フィールド{{ fields }}は無効です
+
+
+ The fields {{ fields }} are missing
+ フィールド{{ fields }}は必須です
+
+
+ This value is not a valid date
+ 値が有効な日付ではありません
+
+
+ This value is not a valid datetime
+ 値が有効な日時ではありません
+
+
+ This value is not a valid email address
+ 値が有効なメールアドレスではありません
+
+
+ The file could not be found
+ ファイルが見つかりません
+
+
+ The file is not readable
+ ファイルを読み込めません
+
+
+ The file is too large ({{ size }}). Allowed maximum size is {{ limit }}
+ ファイルのサイズが大きすぎます({{ size }})。有効な最大サイズは{{ limit }}です
+
+
+ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}
+ ファイルのMIMEタイプが無効です({{ type }})。有効なMIMEタイプは{{ types }}です
+
+
+ This value should be {{ limit }} or less
+ 値は{{ limit }}以下でなければなりません
+
+
+ This value is too long. It should have {{ limit }} characters or less
+ 値が長すぎます。{{ limit }}文字以内でなければなりません
+
+
+ This value should be {{ limit }} or more
+ 値は{{ limit }}以上でなければなりません
+
+
+ This value is too short. It should have {{ limit }} characters or more
+ 値が短すぎます。{{ limit }}文字以上でなければなりません
+
+
+ This value should not be blank
+ 値が空であってはなりません
+
+
+ This value should not be null
+ 値がnullであってはなりません
+
+
+ This value should be null
+ 値はnullでなければなりません
+
+
+ This value is not valid
+ 値が無効です
+
+
+ This value is not a valid time
+ 値が有効な時刻ではありません
+
+
+ This value is not a valid URL
+ 値が有効なURLではありません
+
+
+ This value should be instance of class {{ class }}
+ 値は{{ class }}のインスタンスでなければなりません
+
+
+ This field group should not contain extra fields
+ フィールドグループに追加のフィールドを含んではなりません
+
+
+ The uploaded file was too large. Please try to upload a smaller file
+ アップロードされたファイルが大きすぎます。小さなファイルで再度アップロードしてください
+
+
+ The CSRF token is invalid
+ CSRFトークンが無効です
+
+
+ The two values should be equal
+ 2つの値が同じでなければなりません
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_field.html.php
similarity index 100%
rename from src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_field.php
rename to src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_field.html.php
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/DelegatingEngine.php b/src/Symfony/Bundle/FrameworkBundle/Templating/DelegatingEngine.php
index 438d32ee18d1a..8885834462922 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/DelegatingEngine.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/DelegatingEngine.php
@@ -69,7 +69,7 @@ protected function getEngine($name)
}
}
- throw new \RuntimeException(sprintf('No engine is able to work with the "%s" template.', $name));
+ throw new \RuntimeException(sprintf('No engine is able to work with the %s template.', json_encode($name)));
}
/**
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php
index ff762c31070d0..e6ecf2a3cafe6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php
@@ -53,12 +53,12 @@ public function parse($name)
$parts = explode(':', $name);
if (3 !== count($parts)) {
- throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid (format is "bundle:section:template.engine.format").', $name));
+ throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid (format is "bundle:section:template.format.engine").', $name));
}
$elements = explode('.', $parts[2]);
if (3 !== count($elements)) {
- throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid (format is "bundle:section:template.engine.format").', $name));
+ throw new \InvalidArgumentException(sprintf('Template name "%s" is not valid (format is "bundle:section:template.format.engine").', $name));
}
$parameters = array(
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php
new file mode 100644
index 0000000000000..5f0d3a06a8d13
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php
@@ -0,0 +1,122 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
+use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
+use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
+use Symfony\Bundle\FrameworkBundle\Tests\Logger;
+use Symfony\Bundle\FrameworkBundle\Tests\Kernel;
+
+
+
+/**
+ *
+ * @author Marcin Sikon
+ */
+class RedirectControllerTest extends TestCase
+{
+ public function testEmptyRoute()
+ {
+ $response = new Response();
+
+ $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+ $container
+ ->expects($this->once())
+ ->method('get')
+ ->with($this->equalTo('response'))
+ ->will($this->returnValue($response))
+ ;
+
+ $controller = new RedirectController();
+ $controller->setContainer($container);
+
+ $returnResponse = $controller->redirectAction('');
+
+ $this->assertInstanceOf('\Symfony\Component\HttpFoundation\Response', $returnResponse);
+
+ $this->assertEquals(410, $returnResponse->getStatusCode());
+ }
+
+
+
+ /**
+ * @dataProvider provider
+ */
+ public function testRoute($permanent, $expectedCode)
+ {
+ $response = new Response();
+ $request = new Request();
+
+ $route = 'new-route';
+ $url = '/redirect-url';
+ $params = array('additional-parameter' => 'value');
+
+
+ $request->attributes = new ParameterBag(array('route' => $route, '_route' => 'current-route', 'permanent' => $permanent) + $params);
+
+ $router = $this->getMock('Symfony\Component\Routing\RouterInterface');
+ $router
+ ->expects($this->once())
+ ->method('generate')
+ ->with($this->equalTo($route),$this->equalTo($params))
+ ->will($this->returnValue($url));
+
+ $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+
+
+ $container
+ ->expects($this->at(0))
+ ->method('get')
+ ->with($this->equalTo('request'))
+ ->will($this->returnValue($request));
+
+ $container
+ ->expects($this->at(1))
+ ->method('get')
+ ->with($this->equalTo('response'))
+ ->will($this->returnValue($response));
+
+ $container
+ ->expects($this->at(2))
+ ->method('get')
+ ->with($this->equalTo('router'))
+ ->will($this->returnValue($router));
+
+
+ $controller = new RedirectController();
+ $controller->setContainer($container);
+
+ $returnResponse = $controller->redirectAction($route, $permanent);
+
+
+ $this->assertInstanceOf('\Symfony\Component\HttpFoundation\Response', $returnResponse);
+
+ $this->assertTrue($returnResponse->isRedirect());
+ $this->assertTrue($returnResponse->isRedirected($url));
+ $this->assertEquals($expectedCode, $returnResponse->getStatusCode());
+ }
+
+
+
+ public function provider()
+ {
+ return array(
+ array(true, 301),
+ array(false, 302),
+ );
+ }
+
+}
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..7439b4dc9f972
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
@@ -0,0 +1,46 @@
+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(
+ 'cache_warmer' => true,
+ 'resource' => '%kernel.root_dir%/config/routing.xml',
+ 'type' => 'xml',
+ ),
+ '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..8c508d98e2c38
--- /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..74571b6e6d479
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
@@ -0,0 +1,35 @@
+app.config:
+ csrf_protection:
+ enabled: true
+ field_name: _csrf
+ secret: s3cr3t
+ esi:
+ enabled: true
+ profiler:
+ only_exceptions: true
+ router:
+ cache_warmer: true
+ resource: %kernel.root_dir%/config/routing.xml
+ type: xml
+ 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..95d7d21decfc8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -16,43 +16,183 @@
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->assertEquals('xml', $container->getParameter('router.options.resource_type'), '->registerRouterConfiguration() sets routing resource type');
+ $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..2bb11266c2901
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Configuration.php
@@ -0,0 +1,235 @@
+
+ */
+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')
+ ->performNoDeepMerging()
+ ->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/Extension/FormExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php
index aab5c28c556ee..4f96e842111bf 100644
--- a/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php
+++ b/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php
@@ -123,12 +123,17 @@ public function renderRow(FieldInterface $field)
*
* {{ form_field(field, {}, {'separator': '+++++'}) }}
*
- * @param FieldInterface $field The field to render
- * @param array $params Additional variables passed to the template
- * @param string $resources
+ * @param FieldInterface $field The field to render
+ * @param array $attributes HTML attributes passed to the template
+ * @param array $parameters Additional variables passed to the template
+ * @param array|string $resources A resource or array of resources
*/
public function renderField(FieldInterface $field, array $attributes = array(), array $parameters = array(), $resources = null)
{
+ if (null !== $resources && !is_array($resources)) {
+ $resources = array($resources);
+ }
+
return $this->render($field, 'field', array(
'field' => $field,
'attr' => $attributes,
@@ -190,7 +195,7 @@ public function renderData(FieldInterface $field)
return $field->getData();
}
- protected function render(FieldInterface $field, $name, array $arguments, $resources = null)
+ protected function render(FieldInterface $field, $name, array $arguments, array $resources = null)
{
if ('field' === $name) {
list($name, $template) = $this->getWidget($field, $resources);
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/TwigBundle/TwigEngine.php b/src/Symfony/Bundle/TwigBundle/TwigEngine.php
index 20d7082785c3e..7fdf2d77c2a38 100644
--- a/src/Symfony/Bundle/TwigBundle/TwigEngine.php
+++ b/src/Symfony/Bundle/TwigBundle/TwigEngine.php
@@ -131,6 +131,6 @@ protected function load($name)
return $name;
}
- return $this->environment->loadTemplate($this->parser->parse($name), is_array($name) ? json_encode($name) : $name);
+ return $this->environment->loadTemplate($this->parser->parse($name));
}
}
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/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php
index 02c11dc47968f..dffb1e9327935 100644
--- a/src/Symfony/Component/BrowserKit/Client.php
+++ b/src/Symfony/Component/BrowserKit/Client.php
@@ -266,16 +266,39 @@ protected function getScript($request)
// @codeCoverageIgnoreEnd
}
+ /**
+ * Filters the request.
+ *
+ * @param Request $request The request to filter
+ *
+ * @return Request
+ */
protected function filterRequest(Request $request)
{
return $request;
}
+ /**
+ * Filters the Response.
+ *
+ * @param Response $response The Response to filter
+ *
+ * @return Response
+ */
protected function filterResponse($response)
{
return $response;
}
+ /**
+ * Creates a crawler.
+ *
+ * @param string $uri A uri
+ * @param string $content Content for the crawler to use
+ * @param string $type Content type
+ *
+ * @return Crawler
+ */
protected function createCrawlerFromContent($uri, $content, $type)
{
$crawler = new Crawler(null, $uri);
@@ -286,6 +309,8 @@ protected function createCrawlerFromContent($uri, $content, $type)
/**
* Goes back in the browser history.
+ *
+ * @return Crawler
*/
public function back()
{
@@ -294,6 +319,8 @@ public function back()
/**
* Goes forward in the browser history.
+ *
+ * @return Crawler
*/
public function forward()
{
@@ -302,6 +329,8 @@ public function forward()
/**
* Reloads the current browser.
+ *
+ * @return Crawler
*/
public function reload()
{
@@ -335,6 +364,12 @@ public function restart()
$this->history->clear();
}
+ /**
+ * Takes a URI and converts it to absolute if it is not already absolute.
+ *
+ * @param string $uri A uri
+ * @return string An absolute uri
+ */
protected function getAbsoluteUri($uri)
{
// already absolute?
diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php
index 0ed9a4c064b66..a80129a802ae2 100644
--- a/src/Symfony/Component/BrowserKit/Response.php
+++ b/src/Symfony/Component/BrowserKit/Response.php
@@ -39,6 +39,11 @@ public function __construct($content = '', $status = 200, array $headers = array
$this->headers = $headers;
}
+ /**
+ * Converts the response object to string containing all headers and the response content.
+ *
+ * @return string The response with headers and content
+ */
public function __toString()
{
$headers = '';
diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
index 62e9f4f5dffc3..d5419a06ce769 100644
--- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
+++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
@@ -119,6 +119,10 @@ static public function load($classes, $cacheDir, $name, $autoReload, $adaptive =
/**
* Adds brackets around each namespace if it's not already the case.
+ *
+ * @param string $source Namespace string
+ *
+ * @return string Namespaces with brackets
*/
static public function fixNamespaceDeclarations($source)
{
@@ -162,6 +166,15 @@ static public function fixNamespaceDeclarations($source)
return $output;
}
+ /**
+ * Writes a cache file.
+ *
+ * @param string $file Filename
+ * @param string $content Temporary file content
+ *
+ * @throws \RuntimeException when a cache file cannot be written
+ */
+
static protected function writeCacheFile($file, $content)
{
$tmpFile = tempnam(dirname($file), basename($file));
diff --git a/src/Symfony/Component/ClassLoader/MapFileClassLoader.php b/src/Symfony/Component/ClassLoader/MapFileClassLoader.php
index 8a370af645a85..0a4d5c15e64b7 100644
--- a/src/Symfony/Component/ClassLoader/MapFileClassLoader.php
+++ b/src/Symfony/Component/ClassLoader/MapFileClassLoader.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\ClassLoader;
/**
+ * A class loader that uses a mapping file to look up paths.
*
* @author Fabien Potencier
*/
@@ -19,6 +20,11 @@ class MapFileClassLoader
{
protected $map = array();
+ /**
+ * Constructor.
+ *
+ * @param string $file Path to class mapping file
+ */
public function __construct($file)
{
$this->map = require $file;
diff --git a/src/Symfony/Component/ClassLoader/UniversalClassLoader.php b/src/Symfony/Component/ClassLoader/UniversalClassLoader.php
index 55d3527d57f79..0394fa496e294 100644
--- a/src/Symfony/Component/ClassLoader/UniversalClassLoader.php
+++ b/src/Symfony/Component/ClassLoader/UniversalClassLoader.php
@@ -102,7 +102,7 @@ public function getPrefixFallback()
/**
* Registers the directory to use as a fallback for namespaces.
*
- * @return string|array $dirs A directory path or an array of directories
+ * @param string|array $dirs A directory path or an array of directories
*/
public function registerNamespaceFallback($dirs)
{
@@ -112,7 +112,7 @@ public function registerNamespaceFallback($dirs)
/**
* Registers the directory to use as a fallback for class prefixes.
*
- * @return string|array $dirs A directory path or an array of directories
+ * @param string|array $dirs A directory path or an array of directories
*/
public function registerPrefixFallback($dirs)
{
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 89c31bade7fa0..d7509de85b245 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -201,7 +201,7 @@ public function setHelperSet(HelperSet $helperSet)
}
/**
- * Get the helper set associated with the command
+ * Get the helper set associated with the command.
*
* @return HelperSet The HelperSet instance associated with this command
*/
@@ -396,7 +396,7 @@ public function get($name)
}
/**
- * Returns true if the command exists, false otherwise
+ * Returns true if the command exists, false otherwise.
*
* @param string $name The command name or alias
*
@@ -429,6 +429,8 @@ public function getNamespaces()
/**
* Finds a registered namespace by a name or an abbreviation.
*
+ * @param string $namespace A namespace or abbreviation to search for
+ *
* @return string A registered namespace
*
* @throws \InvalidArgumentException When namespace is incorrect or ambiguous
@@ -715,11 +717,25 @@ public function renderException($e, $output)
}
}
+ /**
+ * Gets the name of the command based on input.
+ *
+ * @param InputInterface $input The input interface
+ *
+ * @return string The command name
+ */
protected function getCommandName(InputInterface $input)
{
return $input->getFirstArgument('command');
}
+ /**
+ * Sorts commands in alphabetical order.
+ *
+ * @param array $commands An associative array of commands to sort
+ *
+ * @return array A sorted array of commands
+ */
protected function sortCommands($commands)
{
$namespacedCommands = array();
@@ -741,6 +757,13 @@ protected function sortCommands($commands)
return $namespacedCommands;
}
+ /**
+ * Returns abbreviated suggestions in string format.
+ *
+ * @param array $abbrevs Abbreviated suggestions to convert
+ *
+ * @return string A formatted string of abbreviated suggestions
+ */
protected function getAbbreviationSuggestions($abbrevs)
{
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
diff --git a/src/Symfony/Component/Console/Command/HelpCommand.php b/src/Symfony/Component/Console/Command/HelpCommand.php
index 49e91782dcde0..61ff032c0a383 100644
--- a/src/Symfony/Component/Console/Command/HelpCommand.php
+++ b/src/Symfony/Component/Console/Command/HelpCommand.php
@@ -28,7 +28,7 @@ class HelpCommand extends Command
protected $command;
/**
- * @see Command
+ * {@inheritdoc}
*/
protected function configure()
{
@@ -54,13 +54,18 @@ protected function configure()
);
}
+ /**
+ * Sets the command
+ *
+ * @param Command $command The command to set
+ */
public function setCommand(Command $command)
{
$this->command = $command;
}
/**
- * @see Command
+ * {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
diff --git a/src/Symfony/Component/Console/Command/ListCommand.php b/src/Symfony/Component/Console/Command/ListCommand.php
index 3d2ee7bb159f8..76fb7cbcefdba 100644
--- a/src/Symfony/Component/Console/Command/ListCommand.php
+++ b/src/Symfony/Component/Console/Command/ListCommand.php
@@ -26,7 +26,7 @@
class ListCommand extends Command
{
/**
- * @see Command
+ * {@inheritdoc}
*/
protected function configure()
{
@@ -54,7 +54,7 @@ protected function configure()
}
/**
- * @see Command
+ * {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
diff --git a/src/Symfony/Component/Console/Helper/FormatterHelper.php b/src/Symfony/Component/Console/Helper/FormatterHelper.php
index 7da190631fad9..5a05aa049a994 100644
--- a/src/Symfony/Component/Console/Helper/FormatterHelper.php
+++ b/src/Symfony/Component/Console/Helper/FormatterHelper.php
@@ -67,6 +67,13 @@ public function formatBlock($messages, $style, $large = false)
return implode("\n", $messages);
}
+ /**
+ * Returns the length of a string, uses mb_strlen if it is available.
+ *
+ * @param string $string The string to check its length
+ *
+ * @return integer The length of the string
+ */
protected function strlen($string)
{
return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
@@ -74,6 +81,8 @@ protected function strlen($string)
/**
* Returns the helper's canonical name
+ *
+ * @return string The canonical name of the helper
*/
public function getName()
{
diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php
index 5662e5f69bdcb..6ad48121442aa 100644
--- a/src/Symfony/Component/Console/Input/ArgvInput.php
+++ b/src/Symfony/Component/Console/Input/ArgvInput.php
@@ -252,4 +252,36 @@ public function hasParameterOption($values)
return false;
}
+
+ /**
+ * Returns the value of a raw option (not parsed).
+ *
+ * This method is to be used to introspect the input parameters
+ * before it has been validated. It must be used carefully.
+ *
+ * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
+ * @param mixed $default The default value to return if no result is found
+ * @return mixed The option value
+ */
+ public function getParameterOption($values, $default = false)
+ {
+ if (!is_array($values)) {
+ $values = array($values);
+ }
+
+ $tokens = $this->tokens;
+ while ($token = array_shift($tokens)) {
+ foreach ($values as $value) {
+ if (0 === strpos($token, $value)) {
+ if (false !== $pos = strpos($token, '=')) {
+ return substr($token, $pos + 1);
+ } else {
+ return array_shift($this->tokens);
+ }
+ }
+ }
+ }
+
+ return $default;
+ }
}
diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php
index e9572d71ed297..56c5fad9ab518 100644
--- a/src/Symfony/Component/Console/Input/ArrayInput.php
+++ b/src/Symfony/Component/Console/Input/ArrayInput.php
@@ -82,6 +82,34 @@ public function hasParameterOption($values)
return false;
}
+ /**
+ * Returns the value of a raw option (not parsed).
+ *
+ * This method is to be used to introspect the input parameters
+ * before it has been validated. It must be used carefully.
+ *
+ * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
+ * @param mixed $default The default value to return if no result is found
+ *
+ * @return mixed The option value
+ */
+ public function getParameterOption($values, $default = false)
+ {
+ if (!is_array($values)) {
+ $values = array($values);
+ }
+
+ foreach ($this->parameters as $k => $v) {
+ if (is_int($k) && in_array($v, $values)) {
+ return true;
+ } elseif (in_array($k, $values)) {
+ return $v;
+ }
+ }
+
+ return $default;
+ }
+
/**
* Processes command line arguments.
*/
diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php
index 8fcf9899251f6..aba45273a7bc9 100644
--- a/src/Symfony/Component/Console/Input/Input.php
+++ b/src/Symfony/Component/Console/Input/Input.php
@@ -64,6 +64,8 @@ public function bind(InputDefinition $definition)
abstract protected function parse();
/**
+ * Validates the input.
+ *
* @throws \RuntimeException When not enough arguments are given
*/
public function validate()
@@ -73,11 +75,21 @@ public function validate()
}
}
+ /**
+ * Checks if the input is interactive.
+ *
+ * @return Boolean Returns true if the input is interactive
+ */
public function isInteractive()
{
return $this->interactive;
}
+ /**
+ * Sets the input interactivity.
+ *
+ * @param Boolean $interactive If the input should be interactive
+ */
public function setInteractive($interactive)
{
$this->interactive = (Boolean) $interactive;
diff --git a/src/Symfony/Component/Console/Input/InputDefinition.php b/src/Symfony/Component/Console/Input/InputDefinition.php
index a4ed4ae3a2a9b..9a7baff2a60e5 100644
--- a/src/Symfony/Component/Console/Input/InputDefinition.php
+++ b/src/Symfony/Component/Console/Input/InputDefinition.php
@@ -42,6 +42,11 @@ public function __construct(array $definition = array())
$this->setDefinition($definition);
}
+ /**
+ * Sets the definition of the input.
+ *
+ * @param array $definition The definition array
+ */
public function setDefinition(array $definition)
{
$arguments = array();
@@ -297,6 +302,8 @@ public function hasShortcut($name)
/**
* Gets an InputOption by shortcut.
*
+ * @param string $shortcut the Shortcut name
+ *
* @return InputOption An InputOption object
*/
public function getOptionForShortcut($shortcut)
diff --git a/src/Symfony/Component/Console/Input/InputInterface.php b/src/Symfony/Component/Console/Input/InputInterface.php
index bf943716a4e1a..53147732987ab 100644
--- a/src/Symfony/Component/Console/Input/InputInterface.php
+++ b/src/Symfony/Component/Console/Input/InputInterface.php
@@ -31,11 +31,24 @@ function getFirstArgument();
* This method is to be used to introspect the input parameters
* before it has been validated. It must be used carefully.
*
- * @param string $value The value to look for in the raw parameters
+ * @param string|array $value The values to look for in the raw parameters (can be an array)
*
* @return Boolean true if the value is contained in the raw parameters
*/
- function hasParameterOption($value);
+ function hasParameterOption($values);
+
+ /**
+ * Returns the value of a raw option (not parsed).
+ *
+ * This method is to be used to introspect the input parameters
+ * before it has been validated. It must be used carefully.
+ *
+ * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
+ * @param mixed $default The default value to return if no result is found
+ *
+ * @return mixed The option value
+ */
+ function getParameterOption($values, $default = false);
/**
* Binds the current Input instance with the given arguments and options.
@@ -63,6 +76,7 @@ function getArguments();
/**
* Get argument by name.
*
+ * @param string $name The name of the argument
* @return mixed
*/
function getArgument($name);
@@ -72,6 +86,12 @@ function getArgument($name);
*/
function getOptions();
+ /**
+ * Get an option by name.
+ *
+ * @param string $name The name of the option
+ * @return mixed
+ */
function getOption($name);
/**
diff --git a/src/Symfony/Component/Console/Input/StringInput.php b/src/Symfony/Component/Console/Input/StringInput.php
index 64d9772af2d99..7a7575996b9c8 100644
--- a/src/Symfony/Component/Console/Input/StringInput.php
+++ b/src/Symfony/Component/Console/Input/StringInput.php
@@ -39,6 +39,9 @@ public function __construct($input, InputDefinition $definition = null)
}
/**
+ * Tokenizes a string.
+ *
+ * @param string $input The input to tokenise
* @throws \InvalidArgumentException When unable to parse input (should never happen)
*/
protected function tokenize($input)
diff --git a/src/Symfony/Component/Console/Output/Output.php b/src/Symfony/Component/Console/Output/Output.php
index 388848614af0c..acc1a2f03c9b2 100644
--- a/src/Symfony/Component/Console/Output/Output.php
+++ b/src/Symfony/Component/Console/Output/Output.php
@@ -179,6 +179,12 @@ protected function format($message)
}
/**
+ * Replaces the starting style of the output.
+ *
+ * @param array $match
+ *
+ * @return string The replaced style
+ *
* @throws \InvalidArgumentException When style is unknown
*/
protected function replaceStartStyle($match)
@@ -220,6 +226,13 @@ protected function replaceStartStyle($match)
return "\033[".implode(';', $codes).'m';
}
+ /**
+ * Replaces the end style.
+ *
+ * @param string $match The text to match
+ *
+ * @return string The end style
+ */
protected function replaceEndStyle($match)
{
if (!$this->decorated) {
diff --git a/src/Symfony/Component/CssSelector/Node/AttribNode.php b/src/Symfony/Component/CssSelector/Node/AttribNode.php
index 30128826cdb28..3471986d2d166 100644
--- a/src/Symfony/Component/CssSelector/Node/AttribNode.php
+++ b/src/Symfony/Component/CssSelector/Node/AttribNode.php
@@ -30,6 +30,15 @@ class AttribNode implements NodeInterface
protected $operator;
protected $value;
+ /**
+ * Constructor.
+ *
+ * @param NodeInterface $selector The XPath selector
+ * @param string $namespace The namespace
+ * @param string $attrib The attribute
+ * @param string $operator The operator
+ * @param string $value The value
+ */
public function __construct($selector, $namespace, $attrib, $operator, $value)
{
$this->selector = $selector;
@@ -39,6 +48,9 @@ public function __construct($selector, $namespace, $attrib, $operator, $value)
$this->value = $value;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
if ($this->operator == 'exists') {
@@ -49,7 +61,7 @@ public function __toString()
}
/**
- * @throws SyntaxError When unknown operator is found
+ * {@inheritDoc}
*/
public function toXpath()
{
@@ -88,6 +100,11 @@ public function toXpath()
return $path;
}
+ /**
+ * Returns the XPath Attribute
+ *
+ * @return string The XPath attribute
+ */
protected function xpathAttrib()
{
// FIXME: if attrib is *?
@@ -98,6 +115,11 @@ protected function xpathAttrib()
return sprintf('@%s:%s', $this->namespace, $this->attrib);
}
+ /**
+ * Returns a formatted attribute
+ *
+ * @return string The formatted attributep
+ */
protected function formatAttrib()
{
if ($this->namespace == '*') {
diff --git a/src/Symfony/Component/CssSelector/Node/ClassNode.php b/src/Symfony/Component/CssSelector/Node/ClassNode.php
index de7e931c4fe57..850b44ec892ea 100644
--- a/src/Symfony/Component/CssSelector/Node/ClassNode.php
+++ b/src/Symfony/Component/CssSelector/Node/ClassNode.php
@@ -26,17 +26,29 @@ class ClassNode implements NodeInterface
protected $selector;
protected $className;
+ /**
+ * The constructor.
+ *
+ * @param NodeInterface $selector The XPath Selector
+ * @param string $className The class name
+ */
public function __construct($selector, $className)
{
$this->selector = $selector;
$this->className = $className;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s[%s.%s]', __CLASS__, $this->selector, $this->className);
}
+ /**
+ * {@inheritDoc}
+ */
public function toXpath()
{
$selXpath = $this->selector->toXpath();
diff --git a/src/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php b/src/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
index 1662d59f58433..80e88e130a51f 100644
--- a/src/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
+++ b/src/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php
@@ -34,6 +34,13 @@ class CombinedSelectorNode implements NodeInterface
protected $combinator;
protected $subselector;
+ /**
+ * The constructor.
+ *
+ * @param NodeInterface $selector The XPath selector
+ * @param string $combinator The combinator
+ * @param NodeInterface $subselector The sub XPath selector
+ */
public function __construct($selector, $combinator, $subselector)
{
$this->selector = $selector;
@@ -41,6 +48,9 @@ public function __construct($selector, $combinator, $subselector)
$this->subselector = $subselector;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
$comb = $this->combinator == ' ' ? '' : $this->combinator;
@@ -49,6 +59,7 @@ public function __toString()
}
/**
+ * {@inheritDoc}
* @throws SyntaxError When unknown combinator is found
*/
public function toXpath()
@@ -63,6 +74,12 @@ public function toXpath()
return $this->$method($path, $this->subselector);
}
+ /**
+ * Joins a NodeInterface into the XPath of this object.
+ *
+ * @param XPathExpr $xpath The XPath expression for this object
+ * @param NodeInterface $sub The NodeInterface object to add
+ */
protected function _xpath_descendant($xpath, $sub)
{
// when sub is a descendant in any way of xpath
@@ -71,6 +88,12 @@ protected function _xpath_descendant($xpath, $sub)
return $xpath;
}
+ /**
+ * Joins a NodeInterface as a child of this object.
+ *
+ * @param XPathExpr $xpath The parent XPath expression
+ * @param NodeInterface $sub The NodeInterface object to add
+ */
protected function _xpath_child($xpath, $sub)
{
// when sub is an immediate child of xpath
@@ -79,6 +102,12 @@ protected function _xpath_child($xpath, $sub)
return $xpath;
}
+ /**
+ * Joins an XPath expression as an adjacent of another.
+ *
+ * @param XPathExpr $xpath The parent XPath expression
+ * @param NodeInterface $sub The adjacent XPath expression
+ */
protected function _xpath_direct_adjacent($xpath, $sub)
{
// when sub immediately follows xpath
@@ -89,6 +118,12 @@ protected function _xpath_direct_adjacent($xpath, $sub)
return $xpath;
}
+ /**
+ * Joins an XPath expression as an indirect adjacent of another.
+ *
+ * @param XPathExpr $xpath The parent XPath expression
+ * @param NodeInterface $sub The indirect adjacent NodeInterface object
+ */
protected function _xpath_indirect_adjacent($xpath, $sub)
{
// when sub comes somewhere after xpath as a sibling
diff --git a/src/Symfony/Component/CssSelector/Node/ElementNode.php b/src/Symfony/Component/CssSelector/Node/ElementNode.php
index 86ffd57721091..683d36562496b 100644
--- a/src/Symfony/Component/CssSelector/Node/ElementNode.php
+++ b/src/Symfony/Component/CssSelector/Node/ElementNode.php
@@ -26,17 +26,31 @@ class ElementNode implements NodeInterface
protected $namespace;
protected $element;
+ /**
+ * Constructor.
+ *
+ * @param string $namespace Namespace
+ * @param string $element Element
+ */
public function __construct($namespace, $element)
{
$this->namespace = $namespace;
$this->element = $element;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s[%s]', __CLASS__, $this->formatElement());
}
+ /**
+ * Formats the element into a string.
+ *
+ * @return string Element as an XPath string
+ */
public function formatElement()
{
if ($this->namespace == '*') {
@@ -46,6 +60,9 @@ public function formatElement()
return sprintf('%s|%s', $this->namespace, $this->element);
}
+ /**
+ * {@inheritDoc}
+ */
public function toXpath()
{
if ($this->namespace == '*') {
diff --git a/src/Symfony/Component/CssSelector/Node/FunctionNode.php b/src/Symfony/Component/CssSelector/Node/FunctionNode.php
index 9f7467b37d23c..8de049672d80e 100644
--- a/src/Symfony/Component/CssSelector/Node/FunctionNode.php
+++ b/src/Symfony/Component/CssSelector/Node/FunctionNode.php
@@ -31,6 +31,14 @@ class FunctionNode implements NodeInterface
protected $name;
protected $expr;
+ /**
+ * Constructor.
+ *
+ * @param NodeInterface $selector The XPath expression
+ * @param string $type
+ * @param string $name
+ * @param XPathExpr $expr
+ */
public function __construct($selector, $type, $name, $expr)
{
$this->selector = $selector;
@@ -39,12 +47,16 @@ public function __construct($selector, $type, $name, $expr)
$this->expr = $expr;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s[%s%s%s(%s)]', __CLASS__, $this->selector, $this->type, $this->name, $this->expr);
}
/**
+ * {@inheritDoc}
* @throws SyntaxError When unsupported or unknown pseudo-class is found
*/
public function toXpath()
@@ -61,6 +73,15 @@ public function toXpath()
return $this->$method($sel_path, $this->expr);
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param mixed $expr
+ * @param string $last
+ * @param string $addNameTest
+ * @return XPathExpr
+ */
protected function _xpath_nth_child($xpath, $expr, $last = false, $addNameTest = true)
{
list($a, $b) = $this->parseSeries($expr);
@@ -124,11 +145,25 @@ protected function _xpath_nth_child($xpath, $expr, $last = false, $addNameTest =
-1n+6 means elements 6 and previous */
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param XPathExpr $expr
+ * @return XPathExpr
+ */
protected function _xpath_nth_last_child($xpath, $expr)
{
return $this->_xpath_nth_child($xpath, $expr, true);
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param XPathExpr $expr
+ * @return XPathExpr
+ */
protected function _xpath_nth_of_type($xpath, $expr)
{
if ($xpath->getElement() == '*') {
@@ -138,11 +173,25 @@ protected function _xpath_nth_of_type($xpath, $expr)
return $this->_xpath_nth_child($xpath, $expr, false, false);
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param XPathExpr $expr
+ * @return XPathExpr
+ */
protected function _xpath_nth_last_of_type($xpath, $expr)
{
return $this->_xpath_nth_child($xpath, $expr, true, false);
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param XPathExpr $expr
+ * @return XPathExpr
+ */
protected function _xpath_contains($xpath, $expr)
{
// text content, minus tags, must contain expr
@@ -159,6 +208,13 @@ protected function _xpath_contains($xpath, $expr)
return $xpath;
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath
+ * @param XPathExpr $expr
+ * @return XPathExpr
+ */
protected function _xpath_not($xpath, $expr)
{
// everything for which not expr applies
@@ -170,7 +226,12 @@ protected function _xpath_not($xpath, $expr)
return $xpath;
}
- // Parses things like '1n+2', or 'an+b' generally, returning (a, b)
+ /**
+ * Parses things like '1n+2', or 'an+b' generally, returning (a, b)
+ *
+ * @param mixed $s
+ * @return array
+ */
protected function parseSeries($s)
{
if ($s instanceof ElementNode) {
diff --git a/src/Symfony/Component/CssSelector/Node/HashNode.php b/src/Symfony/Component/CssSelector/Node/HashNode.php
index 0e72ce0d6ccf6..8c557b547cc58 100644
--- a/src/Symfony/Component/CssSelector/Node/HashNode.php
+++ b/src/Symfony/Component/CssSelector/Node/HashNode.php
@@ -26,17 +26,29 @@ class HashNode implements NodeInterface
protected $selector;
protected $id;
+ /**
+ * Constructor.
+ *
+ * @param NodeInterface $selector The NodeInterface object
+ * @param string $id The ID
+ */
public function __construct($selector, $id)
{
$this->selector = $selector;
$this->id = $id;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s[%s#%s]', __CLASS__, $this->selector, $this->id);
}
+ /**
+ * {@inheritDoc}
+ */
public function toXpath()
{
$path = $this->selector->toXpath();
diff --git a/src/Symfony/Component/CssSelector/Node/NodeInterface.php b/src/Symfony/Component/CssSelector/Node/NodeInterface.php
index f1e8392d045f5..2249617688b12 100644
--- a/src/Symfony/Component/CssSelector/Node/NodeInterface.php
+++ b/src/Symfony/Component/CssSelector/Node/NodeInterface.php
@@ -21,7 +21,17 @@
*/
interface NodeInterface
{
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return string The string representation
+ */
function __toString();
+ /**
+ * @return XPathExpr The XPath expression
+ *
+ * @throws SyntaxError When unknown operator is found
+ */
function toXpath();
}
diff --git a/src/Symfony/Component/CssSelector/Node/OrNode.php b/src/Symfony/Component/CssSelector/Node/OrNode.php
index c0ea77569502a..af13a6caff50c 100644
--- a/src/Symfony/Component/CssSelector/Node/OrNode.php
+++ b/src/Symfony/Component/CssSelector/Node/OrNode.php
@@ -25,16 +25,27 @@ class OrNode implements NodeInterface
{
protected $items;
+ /**
+ * Constructor.
+ *
+ * @param array $items An array of NodeInterface objects
+ */
public function __construct($items)
{
$this->items = $items;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s(%s)', __CLASS__, $this->items);
}
+ /**
+ * {@inheritDoc}
+ */
public function toXpath()
{
$paths = array();
diff --git a/src/Symfony/Component/CssSelector/Node/PseudoNode.php b/src/Symfony/Component/CssSelector/Node/PseudoNode.php
index d55009d68d34c..d0d9166ca4283 100644
--- a/src/Symfony/Component/CssSelector/Node/PseudoNode.php
+++ b/src/Symfony/Component/CssSelector/Node/PseudoNode.php
@@ -34,6 +34,11 @@ class PseudoNode implements NodeInterface
protected $ident;
/**
+ * Constructor.
+ *
+ * @param NodeInterface $element The NodeInterface element
+ * @param string $type Node type
+ * @param string $ident The ident
* @throws SyntaxError When incorrect PseudoNode type is given
*/
public function __construct($element, $type, $ident)
@@ -48,12 +53,16 @@ public function __construct($element, $type, $ident)
$this->ident = $ident;
}
+ /**
+ * {@inheritDoc}
+ */
public function __toString()
{
return sprintf('%s[%s%s%s]', __CLASS__, $this->element, $this->type, $this->ident);
}
/**
+ * {@inheritDoc}
* @throws SyntaxError When unsupported or unknown pseudo-class is found
*/
public function toXpath()
@@ -71,6 +80,11 @@ public function toXpath()
return $this->$method($el_xpath);
}
+ /**
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified XPath expression
+ */
protected function xpath_checked($xpath)
{
// FIXME: is this really all the elements?
@@ -80,6 +94,8 @@ protected function xpath_checked($xpath)
}
/**
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified XPath expression
* @throws SyntaxError If this element is the root element
*/
protected function xpath_root($xpath)
@@ -88,6 +104,12 @@ protected function xpath_root($xpath)
throw new SyntaxError();
}
+ /**
+ * Marks this XPath expression as the first child.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
+ */
protected function xpath_first_child($xpath)
{
$xpath->addStarPrefix();
@@ -97,6 +119,12 @@ protected function xpath_first_child($xpath)
return $xpath;
}
+ /**
+ * Sets the XPath to be the last child.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
+ */
protected function xpath_last_child($xpath)
{
$xpath->addStarPrefix();
@@ -106,6 +134,12 @@ protected function xpath_last_child($xpath)
return $xpath;
}
+ /**
+ * Sets the XPath expression to be the first of type.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
+ */
protected function xpath_first_of_type($xpath)
{
if ($xpath->getElement() == '*') {
@@ -118,6 +152,10 @@ protected function xpath_first_of_type($xpath)
}
/**
+ * Sets the XPath expression to be the last of type.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
* @throws SyntaxError Because *:last-of-type is not implemented
*/
protected function xpath_last_of_type($xpath)
@@ -131,6 +169,12 @@ protected function xpath_last_of_type($xpath)
return $xpath;
}
+ /**
+ * Sets the XPath expression to be the only child.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
+ */
protected function xpath_only_child($xpath)
{
$xpath->addNameTest();
@@ -141,6 +185,10 @@ protected function xpath_only_child($xpath)
}
/**
+ * Sets the XPath expression to be only of type.
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
* @throws SyntaxError Because *:only-of-type is not implemented
*/
protected function xpath_only_of_type($xpath)
@@ -153,6 +201,12 @@ protected function xpath_only_of_type($xpath)
return $xpath;
}
+ /**
+ * undocumented function
+ *
+ * @param XPathExpr $xpath The XPath expression
+ * @return XPathExpr The modified expression
+ */
protected function xpath_empty($xpath)
{
$xpath->addCondition('not(*) and not(normalize-space())');
diff --git a/src/Symfony/Component/CssSelector/Parser.php b/src/Symfony/Component/CssSelector/Parser.php
index 6861f80899b6a..612e556d2607b 100644
--- a/src/Symfony/Component/CssSelector/Parser.php
+++ b/src/Symfony/Component/CssSelector/Parser.php
@@ -25,7 +25,16 @@
class Parser
{
/**
+ * Translates 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::')
}
/**
+ * Parses an expression and returns 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)
}
}
+ /**
+ * Parses a selector group contained in $stream and returns
+ * 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)
}
/**
+ * Parses a selector contained in $stream and returns 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)
}
/**
+ * Parses a simple selector (the current token) from $stream and returns
+ * 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)
}
/**
+ * Parses an attribute from a selector contained in $stream and returns
+ * 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..7f1fdfb4f291d 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;
}
+ /**
+ * Answers 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..bbfbd88213a8f 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;
}
+ /**
+ * Peeks 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..d6f934f5f5f96 100644
--- a/src/Symfony/Component/CssSelector/Tokenizer.php
+++ b/src/Symfony/Component/CssSelector/Tokenizer.php
@@ -21,6 +21,14 @@
*/
class Tokenizer
{
+ /**
+ * Takes a CSS selector and returns 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)
}
/**
+ * Tokenizes a quoted string (i.e. 'A string quoted with \' characters'),
+ * and returns 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)
}
/**
+ * Unescapes a string literal and returns 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)
}
/**
+ * Lexes selector $s and returns 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..d5a54caf06307 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;
}
+ /**
+ * Answers 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;
}
+ /**
+ * Adds 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)
}
}
+ /**
+ * Adds 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)
}
}
+ /**
+ * Adds 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 = '*';
}
+ /**
+ * Adds 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;
}
+ /**
+ * Joins 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..e5b75a5a0a96a 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,56 @@ 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) {
+ // prototype, and key is irrelevant, so simply append the element
+ if (null !== $this->prototype && null === $this->keyAttribute) {
+ $leftSide[] = $v;
+ continue;
+ }
+
+ // 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..3f270bf14cf24 100644
--- a/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php
+++ b/src/Symfony/Component/DependencyInjection/Configuration/ScalarNode.php
@@ -2,10 +2,48 @@
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.
+ *
+ * The following values are considered scalars:
+ * * booleans
+ * * strings
+ * * null
+ * * integers
+ * * floats
+ *
+ * @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;
@@ -13,8 +51,8 @@ public function setName($name)
protected function validateType($value)
{
- if (!is_scalar($value)) {
- throw new \InvalidTypeException(sprintf(
+ if (!is_scalar($value) && null !== $value) {
+ throw new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected scalar, but got %s.',
$this->getPath(),
json_encode($value)
@@ -22,8 +60,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/Form/DateField.php b/src/Symfony/Component/Form/DateField.php
index 3330bad81f765..f08c4733e976f 100644
--- a/src/Symfony/Component/Form/DateField.php
+++ b/src/Symfony/Component/Form/DateField.php
@@ -89,6 +89,19 @@ class DateField extends HybridField
*/
protected $formatter;
+ /**
+ * {@inheritDoc}
+ */
+ public function __construct($key, array $options = array())
+ {
+ // Override parent option
+ // \DateTime objects are never edited by reference, because
+ // we treat them like value objects
+ $this->addOption('by_reference', false);
+
+ parent::__construct($key, $options);
+ }
+
protected function configure()
{
$this->addOption('widget', self::CHOICE, self::$widgets);
diff --git a/src/Symfony/Component/Form/DateTimeField.php b/src/Symfony/Component/Form/DateTimeField.php
index 3002b7f2bfb7c..5f9d96ed8d13e 100644
--- a/src/Symfony/Component/Form/DateTimeField.php
+++ b/src/Symfony/Component/Form/DateTimeField.php
@@ -75,6 +75,19 @@ class DateTimeField extends Form
TimeField::INPUT,
);
+ /**
+ * {@inheritDoc}
+ */
+ public function __construct($key, array $options = array())
+ {
+ // Override parent option
+ // \DateTime objects are never edited by reference, because
+ // we treat them like value objects
+ $this->addOption('by_reference', false);
+
+ parent::__construct($key, $options);
+ }
+
protected function configure()
{
$this->addOption('date_widget', DateField::CHOICE, self::$dateWidgets);
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index 820772bd1bbd3..1cd9f7ff262fb 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -58,6 +58,12 @@ class Form extends Field implements \IteratorAggregate, FormInterface
*/
protected $dataClass;
+ /**
+ * Stores the constructor closure for creating new domain object instances
+ * @var \Closure
+ */
+ protected $dataConstructor;
+
/**
* The context used when creating the form
* @var FormContext
@@ -86,6 +92,7 @@ public static function create(FormContextInterface $context, $name = null, array
public function __construct($name = null, array $options = array())
{
$this->addOption('data_class');
+ $this->addOption('data_constructor');
$this->addOption('csrf_field_name', '_token');
$this->addOption('csrf_provider');
$this->addOption('field_factory');
@@ -93,6 +100,7 @@ public function __construct($name = null, array $options = array())
$this->addOption('virtual', false);
$this->addOption('validator');
$this->addOption('context');
+ $this->addOption('by_reference', true);
if (isset($options['validation_groups'])) {
$options['validation_groups'] = (array)$options['validation_groups'];
@@ -102,6 +110,10 @@ public function __construct($name = null, array $options = array())
$this->dataClass = $options['data_class'];
}
+ if (isset($options['data_constructor'])) {
+ $this->dataConstructor = $options['data_constructor'];
+ }
+
parent::__construct($name, $options);
// Enable CSRF protection
@@ -340,6 +352,16 @@ protected function getFieldsByVisibility($hidden, $recursive)
*/
public function setData($data)
{
+ if (empty($data)) {
+ if ($this->dataConstructor) {
+ $constructor = $this->dataConstructor;
+ $data = $constructor();
+ } else if ($this->dataClass) {
+ $class = $this->dataClass;
+ $data = new $class();
+ }
+ }
+
parent::setData($data);
// get transformed data and pass its values to child fields
@@ -712,6 +734,10 @@ public function getCsrfProvider()
*/
public function bind(Request $request, $data = null)
{
+ if (!$this->getName()) {
+ throw new FormException('You cannot bind anonymous forms. Please give this form a name');
+ }
+
// Store object from which to read the default values and where to
// write the submitted values
if (null !== $data) {
@@ -880,6 +906,21 @@ public function validateData(ExecutionContext $context)
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public function writeProperty(&$objectOrArray)
+ {
+ $data = $this->getData();
+
+ // Don't update parent if data is a composite type (object or array)
+ // and "by_reference" option is true, because then we expect that
+ // we are working with a reference to the parent's data
+ if (!is_object($data) || !is_object($objectOrArray) || !$this->getOption('by_reference')) {
+ parent::writeProperty($objectOrArray);
+ }
+ }
+
/**
* Merges two arrays without reindexing numeric keys.
*
diff --git a/src/Symfony/Component/Form/TimeField.php b/src/Symfony/Component/Form/TimeField.php
index 3f221db2b4bf3..a8961fe7aa830 100644
--- a/src/Symfony/Component/Form/TimeField.php
+++ b/src/Symfony/Component/Form/TimeField.php
@@ -59,6 +59,19 @@ class TimeField extends Form
self::RAW,
);
+ /**
+ * {@inheritDoc}
+ */
+ public function __construct($key, array $options = array())
+ {
+ // Override parent option
+ // \DateTime objects are never edited by reference, because
+ // we treat them like value objects
+ $this->addOption('by_reference', false);
+
+ parent::__construct($key, $options);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/Symfony/Component/Form/ValueTransformer/BooleanToStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/BooleanToStringTransformer.php
index 1a793f5fce149..890b0bc326bfa 100644
--- a/src/Symfony/Component/Form/ValueTransformer/BooleanToStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/BooleanToStringTransformer.php
@@ -47,7 +47,7 @@ public function transform($value)
* @param string $value String value.
* @return Boolean Boolean value.
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (!is_string($value)) {
throw new UnexpectedTypeException($value, 'string');
diff --git a/src/Symfony/Component/Form/ValueTransformer/CollectionToStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/CollectionToStringTransformer.php
deleted file mode 100644
index b939f69236dda..0000000000000
--- a/src/Symfony/Component/Form/ValueTransformer/CollectionToStringTransformer.php
+++ /dev/null
@@ -1,157 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\ValueTransformer;
-
-use Symfony\Component\Form\Configurable;
-use Doctrine\Common\Collections\Collection;
-
-/**
- * Transforms an instance of Doctrine\Common\Collections\Collection into a string of unique names.
- *
- * Use-Cases for this transformer include: List of Tag-Names, List Of Group/User-Names or the like.
- *
- * This transformer only makes sense if you know the list of related collections to be small and
- * that they have a unique identifier field that is of meaning to the user (Tag Names) and is
- * enforced to be unique in the storage.
- *
- * This transformer can cause the following SQL operations to happen in the case of an ORM collection:
- * 1. Initialize the whole collection using one SELECT query
- * 2. For each removed element issue an UPDATE or DELETE stmt (depending on one-to-many or many-to-many)
- * 3. For each inserted element issue an INSERT or UPDATE stmt (depending on one-to-many or many-to-many)
- * 4. Extra updates if necessary by the ORM.
- *
- * @todo Refactor to make 'fieldName' optional (identifier).
- *
- * @author Benjamin Eberlei
- * @author Bernhard Schussek
- */
-class CollectionToStringTransformer extends Configurable implements ValueTransformerInterface
-{
- protected function configure()
- {
- $this->addOption('trim', true);
- $this->addOption('separator', ',');
- $this->addOption('explode_callback', 'explode');
- $this->addOption('implode_callback', 'implode');
- $this->addOption('create_instance_callback', null);
- $this->addRequiredOption('em');
- $this->addRequiredOption('class_name');
- $this->addRequiredOption('field_name');
-
- parent::configure();
- }
-
- /**
- * @param string $value
- * @param Collection $collection
- */
- public function reverseTransform($value, $collection)
- {
- if (strlen(trim($value)) == 0) {
- // don't check for collection count, a straight clear doesnt initialize the collection
- $collection->clear();
- return $collection;
- }
-
- $callback = $this->getOption('explode_callback');
- $values = call_user_func($callback, $this->getOption('separator'), $value);
-
- if ($this->getOption('trim') === true) {
- $values = array_map('trim', $values);
- }
-
- /* @var $em Doctrine\ORM\EntityManager */
- $em = $this->getOption('em');
- $className = $this->getOption('class_name');
- $reflField = $em->getClassMetadata($className)
- ->getReflectionProperty($this->getOption('field_name'));
-
- // 1. removing elements that are not yet present anymore
- foreach ($collection as $object) {
- $uniqueIdent = $reflField->getValue($object);
- $key = array_search($uniqueIdent, $values);
- if (false === $key) {
- $collection->removeElement($object);
- } else {
- // found in the collection, no need to do anything with it so remove it
- unset($values[$key]);
- }
- }
-
- // 2. add elements that are known to the EntityManager but newly connected, query them from the repository
- if (count($values)) {
- $dql = sprintf('SELECT o FROM %s o WHERE o.%s IN (', $className, $this->getOption('field_name'));
- $query = $em->createQuery();
- $needles = array();
- $i = 0;
- foreach ($values as $val) {
- $query->setParameter(++$i, $val);
- $needles[] = '?'.$i;
- }
- $dql .= implode(',', $needles).')';
- $query->setDql($dql);
- $newElements = $query->getResult();
-
- foreach ($newElements as $object) {
- $collection->add($object);
-
- $uniqueIdent = $reflField->getValue($object);
- $key = array_search($uniqueIdent, $values);
- unset($values[$key]);
- }
- }
-
- // 3. new elements that are not in the repository have to be created and persisted then attached:
- if (count($values)) {
- $callback = $this->getOption('create_instance_callback');
- if (!$callback || !is_callable($callback)) {
- throw new TransformationFailedException('Cannot transform list of identifiers, because a new element was detected and it is unknown how to create an instance of this element.');
- }
-
- foreach ($values as $newValue) {
- $newInstance = call_user_func($callback, $newValue);
- if (!($newInstance instanceof $className)) {
- throw new TransformationFailedException(sprintf('Error while trying to create a new instance for the identifier "%s". No new instance was created.', $newValue));
- }
- $collection->add($newInstance);
- $em->persist($newInstance);
- }
- }
-
- return $collection;
- }
-
- /**
- * Transform a Doctrine Collection into a string of identifies with a separator.
- *
- * @param Collection $value
- * @return string
- */
- public function transform($value)
- {
- if (null === $value) {
- return '';
- }
-
- $values = array();
- $em = $this->getOption('em');
- $reflField = $em->getClassMetadata($this->getOption('class_name'))
- ->getReflectionProperty($this->getOption('field_name'));
-
- foreach ($value as $object) {
- $values[] = $reflField->getValue($object);
- }
- $callback = $this->getOption('implode_callback');
-
- return call_user_func($callback, $this->getOption('separator'), $values);
- }
-}
diff --git a/src/Symfony/Component/Form/ValueTransformer/DateTimeToArrayTransformer.php b/src/Symfony/Component/Form/ValueTransformer/DateTimeToArrayTransformer.php
index 1684a10b22a69..e66085c8ee6de 100644
--- a/src/Symfony/Component/Form/ValueTransformer/DateTimeToArrayTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/DateTimeToArrayTransformer.php
@@ -95,7 +95,7 @@ public function transform($dateTime)
* @param array $value Localized date string/array
* @return DateTime Normalized date
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (null === $value) {
return null;
diff --git a/src/Symfony/Component/Form/ValueTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/DateTimeToLocalizedStringTransformer.php
index fd2bb2756e69d..e5cc1ec2268e1 100644
--- a/src/Symfony/Component/Form/ValueTransformer/DateTimeToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/DateTimeToLocalizedStringTransformer.php
@@ -86,7 +86,7 @@ public function transform($dateTime)
* @param string|array $value Localized date string/array
* @return DateTime Normalized date
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
$inputTimezone = $this->getOption('input_timezone');
diff --git a/src/Symfony/Component/Form/ValueTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/DateTimeToStringTransformer.php
index 014b39c4b31f5..17b86d7be468a 100644
--- a/src/Symfony/Component/Form/ValueTransformer/DateTimeToStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/DateTimeToStringTransformer.php
@@ -62,7 +62,7 @@ public function transform($value)
* @param string $value A value as produced by PHP's date() function
* @return DateTime A DateTime object
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (empty($value)) {
return null;
diff --git a/src/Symfony/Component/Form/ValueTransformer/DateTimeToTimestampTransformer.php b/src/Symfony/Component/Form/ValueTransformer/DateTimeToTimestampTransformer.php
index 3be5fc6c115e3..c05575f0da0b7 100644
--- a/src/Symfony/Component/Form/ValueTransformer/DateTimeToTimestampTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/DateTimeToTimestampTransformer.php
@@ -60,7 +60,7 @@ public function transform($value)
* @param string $value A value as produced by PHP's date() function
* @return DateTime A DateTime object
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (null === $value) {
return null;
diff --git a/src/Symfony/Component/Form/ValueTransformer/MoneyToLocalizedStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/MoneyToLocalizedStringTransformer.php
index 15acd97207cb3..8db5b4cad9b31 100644
--- a/src/Symfony/Component/Form/ValueTransformer/MoneyToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/MoneyToLocalizedStringTransformer.php
@@ -58,9 +58,9 @@ public function transform($value)
* @param string $value Localized money string
* @return number Normalized number
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
- $value = parent::reverseTransform($value, $originalValue);
+ $value = parent::reverseTransform($value);
if (null !== $value) {
$value *= $this->getOption('divisor');
diff --git a/src/Symfony/Component/Form/ValueTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/NumberToLocalizedStringTransformer.php
index a960dbdf62c8f..19d9e3012d5f6 100644
--- a/src/Symfony/Component/Form/ValueTransformer/NumberToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/NumberToLocalizedStringTransformer.php
@@ -74,7 +74,7 @@ public function transform($value)
*
* @param string $value
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (!is_string($value)) {
throw new UnexpectedTypeException($value, 'string');
diff --git a/src/Symfony/Component/Form/ValueTransformer/PercentToLocalizedStringTransformer.php b/src/Symfony/Component/Form/ValueTransformer/PercentToLocalizedStringTransformer.php
index a3762ee788ffb..ece2e4da90476 100644
--- a/src/Symfony/Component/Form/ValueTransformer/PercentToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/PercentToLocalizedStringTransformer.php
@@ -82,7 +82,7 @@ public function transform($value)
* @param number $value Percentage value.
* @return number Normalized value.
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
if (!is_string($value)) {
throw new UnexpectedTypeException($value, 'string');
diff --git a/src/Symfony/Component/Form/ValueTransformer/ReversedTransformer.php b/src/Symfony/Component/Form/ValueTransformer/ReversedTransformer.php
index 93c068b81839f..99af8c16da5b6 100644
--- a/src/Symfony/Component/Form/ValueTransformer/ReversedTransformer.php
+++ b/src/Symfony/Component/Form/ValueTransformer/ReversedTransformer.php
@@ -48,7 +48,7 @@ public function transform($value)
/**
* {@inheritDoc}
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
return $this->reversedTransformer->transform($value);
}
diff --git a/src/Symfony/Component/Form/ValueTransformer/ValueTransformerChain.php b/src/Symfony/Component/Form/ValueTransformer/ValueTransformerChain.php
index a8bbda4dbfba3..129df2dc34c7d 100644
--- a/src/Symfony/Component/Form/ValueTransformer/ValueTransformerChain.php
+++ b/src/Symfony/Component/Form/ValueTransformer/ValueTransformerChain.php
@@ -66,10 +66,10 @@ public function transform($value)
* @param mixed $value The transformed value
* @return mixed The reverse-transformed value
*/
- public function reverseTransform($value, $originalValue)
+ public function reverseTransform($value)
{
for ($i = count($this->transformers) - 1; $i >= 0; --$i) {
- $value = $this->transformers[$i]->reverseTransform($value, $originalValue);
+ $value = $this->transformers[$i]->reverseTransform($value);
}
return $value;
diff --git a/src/Symfony/Component/Form/ValueTransformer/ValueTransformerInterface.php b/src/Symfony/Component/Form/ValueTransformer/ValueTransformerInterface.php
index 663011d5b8ecd..b170b7412a2ea 100644
--- a/src/Symfony/Component/Form/ValueTransformer/ValueTransformerInterface.php
+++ b/src/Symfony/Component/Form/ValueTransformer/ValueTransformerInterface.php
@@ -65,11 +65,9 @@ function transform($value);
* is passed.
*
* @param mixed $value The value in the transformed representation
- * @param mixed $originalValue The original value from the datasource that is about to be overwritten by the new value.
- * @return mixed The value in the original representation
* @throws UnexpectedTypeException when the argument is not of the
* expected type
* @throws ValueTransformerException when the transformation fails
*/
- function reverseTransform($value, $originalValue);
+ function reverseTransform($value);
}
\ No newline at end of file
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/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php
index 7ea2d59cdfa7d..0aee4cd978cee 100644
--- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php
+++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php
@@ -50,17 +50,10 @@ public function guess($path)
return null;
}
- if (!$finfo = new \finfo(FILEINFO_MIME)) {
+ if (!$finfo = new \finfo(FILEINFO_MIME_TYPE)) {
return null;
}
- $type = $finfo->file($path);
-
- // remove charset (added as of PHP 5.3)
- if (false !== $pos = strpos($type, ';')) {
- $type = substr($type, 0, $pos);
- }
-
- return $type;
+ return $finfo->file($path);
}
}
\ No newline at end of file
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 18a3a1c11583f..57883272c457b 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -223,14 +223,34 @@ static public function create($uri, $method = 'GET', $parameters = array(), $coo
public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
{
$dup = clone $this;
- $dup->initialize(
- null !== $query ? $query : $this->query->all(),
- null !== $request ? $request : $this->request->all(),
- null !== $attributes ? $attributes : $this->attributes->all(),
- null !== $cookies ? $cookies : $this->cookies->all(),
- null !== $files ? $files : $this->files->all(),
- null !== $server ? $server : $this->server->all()
- );
+ if ($query !== null) {
+ $dup->query = new ParameterBag($query);
+ }
+ if ($request !== null) {
+ $dup->request = new ParameterBag($request);
+ }
+ if ($attributes !== null) {
+ $dup->attributes = new ParameterBag($attributes);
+ }
+ if ($cookies !== null) {
+ $dup->cookies = new ParameterBag($cookies);
+ }
+ if ($files !== null) {
+ $dup->files = new FileBag($files);
+ }
+ if ($server !== null) {
+ $dup->server = new ServerBag($server);
+ $dup->headers = new HeaderBag($dup->server->getHeaders());
+ }
+ $this->languages = null;
+ $this->charsets = null;
+ $this->acceptableContentTypes = null;
+ $this->pathInfo = null;
+ $this->requestUri = null;
+ $this->baseUrl = null;
+ $this->basePath = null;
+ $this->method = null;
+ $this->format = null;
return $dup;
}
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/Controller/ControllerResolverInterface.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php
index fc7b1de3238e0..0f44beb246abf 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php
@@ -49,6 +49,8 @@ function getController(Request $request);
* @param Request $request A Request instance
* @param mixed $controller A PHP callable
*
+ * @return array An array of arguments to pass to the controller
+ *
* @throws \RuntimeException When value for argument given is not provided
*/
function getArguments(Request $request, $controller);
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
index 0af971fbe8b0a..dfe47a59cbd89 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
@@ -39,6 +39,11 @@ public function collect(Request $request, Response $response, \Exception $except
$responseHeaders['Set-Cookie'] = $cookies;
}
+ $attributes = array();
+ foreach ($request->attributes->all() as $key => $value) {
+ $attributes[$key] = is_object($value) ? sprintf('Object(%s)', get_class($value)) : $value;
+ }
+
$this->data = array(
'format' => $request->getRequestFormat(),
'content_type' => $response->headers->get('Content-Type') ? $response->headers->get('Content-Type') : 'text/html',
@@ -48,7 +53,7 @@ public function collect(Request $request, Response $response, \Exception $except
'request_headers' => $request->headers->all(),
'request_server' => $request->server->all(),
'request_cookies' => $request->cookies->all(),
- 'request_attributes' => $request->attributes->all(),
+ 'request_attributes' => $attributes,
'response_headers' => $responseHeaders,
'session_attributes' => $request->hasSession() ? $request->getSession()->getAttributes() : array(),
);
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
index f4359f0285ea9..cadbfa9f83263 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
@@ -31,6 +31,7 @@ class HttpCache implements HttpKernelInterface
protected $store;
protected $request;
protected $esi;
+ protected $esiTtls;
/**
* Constructor.
@@ -136,6 +137,7 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
if (HttpKernelInterface::MASTER_REQUEST === $type) {
$this->traces = array();
$this->request = $request;
+ $this->esiTtls = array();
}
$path = $request->getPathInfo();
@@ -160,9 +162,44 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
$response->headers->set('X-Symfony-Cache', $this->getLog());
}
+ if (null !== $this->esi) {
+ $this->addEsiTtl($response);
+
+ if ($request === $this->request) {
+ $this->updateResponseCacheControl($response);
+ }
+ }
+
return $response;
}
+ /**
+ * Stores the response's TTL locally.
+ *
+ * @param Response $response
+ */
+ protected function addEsiTtl(Response $response)
+ {
+ $this->esiTtls[] = $response->isValidateable() ? -1 : $response->getTtl();
+ }
+
+ /**
+ * Changes the master response TTL to the smallest TTL received or force validation if
+ * one of the ESI has validation cache strategy.
+ *
+ * @param Response $response
+ */
+ protected function updateResponseCacheControl(Response $response)
+ {
+ $ttl = min($this->esiTtls);
+ if (-1 === $ttl) {
+ $response->headers->set('Cache-Control', 'no-cache, must-revalidate');
+ } else {
+ $response->setSharedMaxAge($ttl);
+ $response->setMaxAge(0);
+ }
+ }
+
/**
* Forwards the Request to the backend without storing the Response in the cache.
*
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index c46d9bf1a150c..86b7ebbe9dc24 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -97,7 +97,7 @@ public function boot()
// init container
$this->initializeContainer();
- foreach ($this->bundles as $bundle) {
+ foreach ($this->getBundles() as $bundle) {
$bundle->setContainer($this->container);
$bundle->boot();
}
@@ -114,7 +114,7 @@ public function shutdown()
{
$this->booted = false;
- foreach ($this->bundles as $bundle) {
+ foreach ($this->getBundles() as $bundle) {
$bundle->shutdown();
$bundle->setContainer(null);
}
@@ -131,7 +131,17 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ
$this->boot();
}
- return $this->container->get('http_kernel')->handle($request, $type, $catch);
+ return $this->getHttpKernel()->handle($request, $type, $catch);
+ }
+
+ /**
+ * Gets a http kernel from the container
+ *
+ * @return HttpKernel
+ */
+ protected function getHttpKernel()
+ {
+ return $this->container->get('http_kernel');
}
/**
@@ -153,7 +163,7 @@ public function getBundles()
*/
public function isClassInActiveBundle($class)
{
- foreach ($this->bundles as $bundle) {
+ foreach ($this->getBundles() as $bundle) {
$bundleClass = get_class($bundle);
if (0 === strpos($class, substr($bundleClass, 0, strrpos($bundleClass, '\\')))) {
return true;
@@ -237,7 +247,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;
}
@@ -343,7 +353,7 @@ protected function initializeBundles()
$this->bundles = array();
$topMostBundles = array();
$directChildren = array();
-
+
foreach ($this->registerBundles() as $bundle) {
$name = $bundle->getName();
if (isset($this->bundles[$name])) {
@@ -358,11 +368,11 @@ protected function initializeBundles()
$directChildren[$parentName] = $name;
} else {
$topMostBundles[$name] = $bundle;
- }
+ }
}
// look for orphans
- if (count($diff = array_diff(array_keys($directChildren), array_keys($this->bundles)))) {
+ if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) {
throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
}
@@ -377,7 +387,7 @@ protected function initializeBundles()
array_unshift($bundleMap, $this->bundles[$name]);
$hierarchy[] = $name;
}
-
+
foreach ($hierarchy as $bundle) {
$this->bundleMap[$bundle] = $bundleMap;
array_pop($bundleMap);
diff --git a/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
index 25d4cc1f5f77c..0840f8649d22d 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/SQLiteProfilerStorage.php
@@ -94,11 +94,11 @@ public function write($token, $data, $ip, $url, $time)
);
try {
$this->exec($db, 'INSERT INTO data (token, data, ip, url, time, created_at) VALUES (:token, :data, :ip, :url, :time, :created_at)', $args);
+ $this->cleanup();
$status = true;
} catch (\Exception $e) {
$status = false;
}
- $this->cleanup();
$this->close($db);
return $status;
@@ -146,6 +146,11 @@ protected function initDb()
protected function exec($db, $query, array $args = array())
{
$stmt = $db->prepare($query);
+
+ if (false === $stmt) {
+ throw new \RuntimeException('The database cannot successfully prepare the statement');
+ }
+
if ($db instanceof \SQLite3) {
foreach ($args as $arg => $val) {
$stmt->bindValue($arg, $val, is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT);
@@ -157,7 +162,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..75e70a9a93926 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;
}
@@ -1233,14 +1243,34 @@ static public function create($uri, $method = 'GET', $parameters = array(), $coo
public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
{
$dup = clone $this;
- $dup->initialize(
- null !== $query ? $query : $this->query->all(),
- null !== $request ? $request : $this->request->all(),
- null !== $attributes ? $attributes : $this->attributes->all(),
- null !== $cookies ? $cookies : $this->cookies->all(),
- null !== $files ? $files : $this->files->all(),
- null !== $server ? $server : $this->server->all()
- );
+ if ($query !== null) {
+ $dup->query = new ParameterBag($query);
+ }
+ if ($request !== null) {
+ $dup->request = new ParameterBag($request);
+ }
+ if ($attributes !== null) {
+ $dup->attributes = new ParameterBag($attributes);
+ }
+ if ($cookies !== null) {
+ $dup->cookies = new ParameterBag($cookies);
+ }
+ if ($files !== null) {
+ $dup->files = new FileBag($files);
+ }
+ if ($server !== null) {
+ $dup->server = new ServerBag($server);
+ $dup->headers = new HeaderBag($dup->server->getHeaders());
+ }
+ $this->languages = null;
+ $this->charsets = null;
+ $this->acceptableContentTypes = null;
+ $this->pathInfo = null;
+ $this->requestUri = null;
+ $this->baseUrl = null;
+ $this->basePath = null;
+ $this->method = null;
+ $this->format = null;
return $dup;
}
public function __clone()
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/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php
index cc90ee8dc1ffc..1a39019abd799 100644
--- a/src/Symfony/Component/Routing/Router.php
+++ b/src/Symfony/Component/Routing/Router.php
@@ -35,8 +35,9 @@ class Router implements RouterInterface
*
* Available options:
*
- * * cache_dir: The cache directory (or null to disable caching)
- * * debug: Whether to enable debugging or not (false by default)
+ * * cache_dir: The cache directory (or null to disable caching)
+ * * debug: Whether to enable debugging or not (false by default)
+ * * resource_type: Type hint for the main resource (optional)
*
* @param LoaderInterface $loader A LoaderInterface instance
* @param mixed $resource The main resource to load
@@ -63,6 +64,7 @@ public function __construct(LoaderInterface $loader, $resource, array $options =
'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
'matcher_cache_class' => 'ProjectUrlMatcher',
+ 'resource_type' => null,
);
// check option names
@@ -81,7 +83,7 @@ public function __construct(LoaderInterface $loader, $resource, array $options =
public function getRouteCollection()
{
if (null === $this->collection) {
- $this->collection = $this->loader->load($this->resource);
+ $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
}
return $this->collection;
diff --git a/src/Symfony/Component/Templating/DelegatingEngine.php b/src/Symfony/Component/Templating/DelegatingEngine.php
index 9c558961dea7f..8717ef0f3d620 100644
--- a/src/Symfony/Component/Templating/DelegatingEngine.php
+++ b/src/Symfony/Component/Templating/DelegatingEngine.php
@@ -103,6 +103,15 @@ public function supports($name)
return false;
}
+ /**
+ * Get an engine able to render the given template.
+ *
+ * @param string $name A template name
+ *
+ * @return EngineInterface The engine
+ *
+ * @throws \RuntimeException if no engine able to work with the template is found
+ */
protected function getEngine($name)
{
foreach ($this->engines as $engine) {
diff --git a/src/Symfony/Component/Templating/PhpEngine.php b/src/Symfony/Component/Templating/PhpEngine.php
index c38898383d671..4fbaf13bb06c4 100644
--- a/src/Symfony/Component/Templating/PhpEngine.php
+++ b/src/Symfony/Component/Templating/PhpEngine.php
@@ -221,6 +221,11 @@ public function addHelpers(array $helpers = array())
}
}
+ /**
+ * Sets the helpers.
+ *
+ * @params Helper[] $helpers An array of helper
+ */
public function setHelpers(array $helpers)
{
$this->helpers = array();
@@ -286,7 +291,8 @@ public function extend($template)
/**
* Escapes a string by using the current charset.
*
- * @param mixed $value A variable to escape
+ * @param mixed $value A variable to escape
+ * @param string $context The context name
*
* @return string The escaped value
*/
@@ -440,6 +446,17 @@ function ($value) use ($that)
);
}
+ /**
+ * Convert a string from one encoding to another.
+ *
+ * @param string $string The string to convert
+ * @param string $to The input encoding
+ * @param string $from The output encoding
+ *
+ * @return string The string with the new encoding
+ *
+ * @throws \RuntimeException if no suitable encoding function is found (iconv or mbstring)
+ */
public function convertEncoding($string, $to, $from)
{
if (function_exists('iconv')) {
diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php
index bb7f3057fc7e5..9cc7b5932b21a 100644
--- a/src/Symfony/Component/Yaml/Inline.php
+++ b/src/Symfony/Component/Yaml/Inline.php
@@ -379,6 +379,11 @@ static protected function evaluateScalar($scalar)
}
}
+ /**
+ * Get a regex that match a unix timestamp
+ *
+ * @return string The regular expression
+ */
static protected function getTimestampRegex()
{
return <<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..64fc6da4eda72
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/MergeTest.php
@@ -0,0 +1,170 @@
+root('root', 'array')
+ ->node('foo', 'scalar')
+ ->cannotBeOverwritten()
+ ->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')
+ ->canBeUnset()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->end()
+ ->node('unsetted', 'array')
+ ->canBeUnset()
+ ->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));
+ }
+
+ public function testPrototypeWithoutAKeyAttribute()
+ {
+ $tb = new TreeBuilder();
+
+ $tree = $tb
+ ->root('config', 'array')
+ ->node('append_elements', 'array')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'append_elements' => array('a', 'b'),
+ );
+
+ $b = array(
+ 'append_elements' => array('c', 'd'),
+ );
+
+ $this->assertEquals(array('append_elements' => array('a', 'b', '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/Configuration/ScalarNodeTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/ScalarNodeTest.php
new file mode 100644
index 0000000000000..8ff43ca073b46
--- /dev/null
+++ b/tests/Symfony/Tests/Component/DependencyInjection/Configuration/ScalarNodeTest.php
@@ -0,0 +1,49 @@
+assertSame($value, $node->normalize($value));
+ }
+
+ public function getValidValues()
+ {
+ return array(
+ array(false),
+ array(true),
+ array(null),
+ array(''),
+ array('foo'),
+ array(0),
+ array(1),
+ array(0.0),
+ array(0.1),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidValues
+ * @expectedException Symfony\Component\DependencyInjection\Configuration\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionOnInvalidValues($value)
+ {
+ $node = new ScalarNode('test');
+ $node->normalize($value);
+ }
+
+ public function getInvalidValues()
+ {
+ return array(
+ array(array()),
+ array(array('foo' => 'bar')),
+ array(new \stdClass()),
+ );
+ }
+}
\ No newline at end of file
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/Form/FormTest.php b/tests/Symfony/Tests/Component/Form/FormTest.php
index 128fd50f6437d..da609f48b27ba 100644
--- a/tests/Symfony/Tests/Component/Form/FormTest.php
+++ b/tests/Symfony/Tests/Component/Form/FormTest.php
@@ -41,6 +41,59 @@ protected function configure()
}
}
+// behaves like a form with a value transformer that transforms into
+// a specific format
+class FormTest_FormThatReturns extends Form
+{
+ protected $returnValue;
+
+ public function setReturnValue($returnValue)
+ {
+ $this->returnValue = $returnValue;
+ }
+
+ public function setData($data)
+ {
+ }
+
+ public function getData()
+ {
+ return $this->returnValue;
+ }
+}
+
+class FormTest_AuthorWithoutRefSetter
+{
+ protected $reference;
+
+ protected $referenceCopy;
+
+ public function __construct($reference)
+ {
+ $this->reference = $reference;
+ $this->referenceCopy = $reference;
+ }
+
+ // The returned object should be modified by reference without having
+ // to provide a setReference() method
+ public function getReference()
+ {
+ return $this->reference;
+ }
+
+ // The returned object is a copy, so setReferenceCopy() must be used
+ // to update it
+ public function getReferenceCopy()
+ {
+ return is_object($this->referenceCopy) ? clone $this->referenceCopy : $this->referenceCopy;
+ }
+
+ public function setReferenceCopy($reference)
+ {
+ $this->referenceCopy = $reference;
+ }
+}
+
class TestSetDataBeforeConfigureForm extends Form
{
protected $testCase;
@@ -223,6 +276,16 @@ public function testValidationGroupsAreNotInheritedFromParentIfSet()
$this->assertEquals(array('group2'), $childForm->getValidationGroups());
}
+ /**
+ * @expectedException Symfony\Component\Form\Exception\FormException
+ */
+ public function testBindThrowsExceptionIfAnonymous()
+ {
+ $form = new Form(null, array('validator' => $this->createMockValidator()));
+
+ $form->bind($this->createPostRequest());
+ }
+
public function testBindValidatesData()
{
$form = new Form('author', array(
@@ -928,6 +991,37 @@ public function testSetDataMatchesAgainstDataClass_succeeds()
$form->setData(new Author());
}
+ public function testSetDataToNull()
+ {
+ $form = new Form('author');
+ $form->setData(null);
+
+ $this->assertNull($form->getData());
+ }
+
+ public function testSetDataToNullCreatesObjectIfClassAvailable()
+ {
+ $form = new Form('author', array(
+ 'data_class' => 'Symfony\Tests\Component\Form\Fixtures\Author',
+ ));
+ $form->setData(null);
+
+ $this->assertEquals(new Author(), $form->getData());
+ }
+
+ public function testSetDataToNullUsesDataConstructorOption()
+ {
+ $author = new Author();
+ $form = new Form('author', array(
+ 'data_constructor' => function () use ($author) {
+ return $author;
+ }
+ ));
+ $form->setData(null);
+
+ $this->assertSame($author, $form->getData());
+ }
+
public function testSubmitUpdatesTransformedDataFromAllFields()
{
$originalAuthor = new Author();
@@ -1130,6 +1224,94 @@ public function testValidateDataDoesNotWalkScalars()
$form->validateData($context);
}
+ public function testSubformDoesntCallSetters()
+ {
+ $author = new FormTest_AuthorWithoutRefSetter(new Author());
+
+ $form = new Form('author', array('validator' => $this->createMockValidator()));
+ $form->setData($author);
+ $refForm = new Form('reference');
+ $refForm->add(new TestField('firstName'));
+ $form->add($refForm);
+
+ $form->bind($this->createPostRequest(array(
+ 'author' => array(
+ // reference has a getter, but not setter
+ 'reference' => array(
+ 'firstName' => 'Foo',
+ )
+ )
+ )));
+
+ $this->assertEquals('Foo', $author->getReference()->firstName);
+ }
+
+ public function testSubformCallsSettersIfByReferenceIsFalse()
+ {
+ $author = new FormTest_AuthorWithoutRefSetter(new Author());
+
+ $form = new Form('author', array('validator' => $this->createMockValidator()));
+ $form->setData($author);
+ $refForm = new Form('referenceCopy', array('by_reference' => false));
+ $refForm->add(new TestField('firstName'));
+ $form->add($refForm);
+
+ $form->bind($this->createPostRequest(array(
+ 'author' => array(
+ // referenceCopy has a getter that returns a copy
+ 'referenceCopy' => array(
+ 'firstName' => 'Foo',
+ )
+ )
+ )));
+
+ // firstName can only be updated if setReferenceCopy() was called
+ $this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
+ }
+
+ public function testSubformCallsSettersIfReferenceIsScalar()
+ {
+ $author = new FormTest_AuthorWithoutRefSetter('scalar');
+
+ $form = new Form('author', array('validator' => $this->createMockValidator()));
+ $form->setData($author);
+ $refForm = new FormTest_FormThatReturns('referenceCopy');
+ $refForm->setReturnValue('foobar');
+ $form->add($refForm);
+
+ $form->bind($this->createPostRequest(array(
+ 'author' => array(
+ 'referenceCopy' => array(), // doesn't matter actually
+ )
+ )));
+
+ // firstName can only be updated if setReferenceCopy() was called
+ $this->assertEquals('foobar', $author->getReferenceCopy());
+ }
+
+ public function testSubformAlwaysInsertsIntoArrays()
+ {
+ $ref1 = new Author();
+ $ref2 = new Author();
+ $author = array('referenceCopy' => $ref1);
+
+ $form = new Form('author', array('validator' => $this->createMockValidator()));
+ $form->setData($author);
+ $refForm = new FormTest_FormThatReturns('referenceCopy');
+ $refForm->setReturnValue($ref2);
+ $form->add($refForm);
+
+ $form->bind($this->createPostRequest(array(
+ 'author' => array(
+ 'referenceCopy' => array(), // doesn't matter actually
+ )
+ )));
+
+ // the new reference was inserted into the array
+ $author = $form->getData();
+ $this->assertSame($ref2, $author['referenceCopy']);
+ }
+
/**
* Create a group containing two fields, "visibleField" and "hiddenField"
*
diff --git a/tests/Symfony/Tests/Component/Form/ValueTransformer/CollectionToStringTransformerTest.php b/tests/Symfony/Tests/Component/Form/ValueTransformer/CollectionToStringTransformerTest.php
deleted file mode 100644
index 97565c4070cec..0000000000000
--- a/tests/Symfony/Tests/Component/Form/ValueTransformer/CollectionToStringTransformerTest.php
+++ /dev/null
@@ -1,223 +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\Form\ValueTransformer;
-
-require_once __DIR__.'/../DoctrineOrmTestCase.php';
-
-use Symfony\Tests\Component\Form\DoctrineOrmTestCase;
-use Symfony\Component\Form\ValueTransformer\CollectionToStringTransformer;
-use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\ORM\Tools\SchemaTool;
-
-class CollectionToStringTransformerTest extends DoctrineOrmTestCase
-{
- /**
- * @var EntityManager
- */
- private $em;
-
- protected function setUp()
- {
- parent::setUp();
- $this->em = $this->createTestEntityManager();
-
- $schemaTool = new SchemaTool($this->em);
- $classes = array($this->em->getClassMetadata(__NAMESPACE__.'\Tag'));
- try {
- $schemaTool->dropSchema($classes);
- } catch(\Exception $e) {
-
- }
- try {
- $schemaTool->createSchema($classes);
- } catch(\Exception $e) {
- echo $e->getMessage();
- }
- }
-
- public function testNoEntityManagerThrowsException()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException');
- $transformer = new CollectionToStringTransformer(array(
- 'class_name' => __NAMESPACE__.'\Tag',
- 'field_name' => 'name',
- ));
- }
-
- public function testNoClassNameThrowsException()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException');
- $transformer = new CollectionToStringTransformer(array(
- 'field_name' => 'name',
- 'em' => $this->em,
- ));
- }
-
- public function testNoFieldNameThrowsException()
- {
- $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException');
- $transformer = new CollectionToStringTransformer(array(
- 'class_name' => __NAMESPACE__.'\Tag',
- 'em' => $this->em,
- ));
- }
-
- public function createTransformer()
- {
- $transformer = new CollectionToStringTransformer(array(
- 'class_name' => __NAMESPACE__.'\Tag',
- 'field_name' => 'name',
- 'em' => $this->em,
- 'create_instance_callback' => function($tagName) {
- return new Tag($tagName);
- }
- ));
- return $transformer;
- }
-
- public function testTransformEmptyCollection()
- {
- $transformer = $this->createTransformer();
- $ret = $transformer->transform(new ArrayCollection());
-
- $this->assertEquals("", $ret);
- }
-
- /**
- * @depends testTransformEmptyCollection
- */
- public function testTransformCollection()
- {
- $transformer = $this->createTransformer();
-
- $tags = new ArrayCollection();
- $tags->add(new Tag("foo"));
- $tags->add(new Tag("bar"));
-
- $this->assertEquals("foo,bar", $transformer->transform($tags));
- }
-
- public function createTagCollection()
- {
- $tags = new ArrayCollection();
- $tags->add(new Tag("foo"));
- $tags->add(new Tag("bar"));
-
- return $tags;
- }
-
- /**
- * @depends testTransformEmptyCollection
- */
- public function testReverseTransformEmptyString()
- {
- $transformer = $this->createTransformer();
-
- $col = new ArrayCollection();
-
- $newCol = $transformer->reverseTransform("", $col);
- $this->assertSame($col, $newCol, "A collection is an expenive object that is re-used by the transformer!");
- $this->assertEquals(0, count($newCol));
- }
-
- /**
- * @depends testReverseTransformEmptyString
- */
- public function testReverseTransformEmptyStringEmptiesCollection()
- {
- $transformer = $this->createTransformer();
-
- $col = $this->createTagCollection();
-
- $newCol = $transformer->reverseTransform("", $col);
- $this->assertSame($col, $newCol, "A collection is an expenive object that is re-used by the transformer!");
- $this->assertEquals(0, count($newCol));
- }
-
- /**
- * @depends testTransformEmptyCollection
- */
- public function testReverseTransformUnchanged()
- {
- $transformer = $this->createTransformer();
-
- $tags = $this->createTagCollection();
-
- $tags = $transformer->reverseTransform("foo,bar", $tags);
-
- $this->assertEquals(2, count($tags));
- }
-
- /**
- * @depends testTransformEmptyCollection
- */
- public function testReverseTransformNewKnownEntity()
- {
- $transformer = $this->createTransformer();
-
- $newTag = new Tag("baz");
- $this->em->persist($newTag);
- $this->em->flush();
-
- $tags = $this->createTagCollection();
- $tags = $transformer->reverseTransform("foo, bar, baz", $tags);
-
- $this->assertEquals(3, count($tags));
- $this->assertTrue($tags->contains($newTag));
- }
-
- /**
- * @depends testReverseTransformNewKnownEntity
- */
- public function testReverseTransformNewUnknownEntity()
- {
- $transformer = $this->createTransformer();
-
- $tags = $this->createTagCollection();
- $tags = $transformer->reverseTransform("foo, bar, baz", $tags);
-
- $this->assertEquals(3, count($tags));
- $this->em->flush();
-
- $this->assertSame($this->em, $transformer->getOption('em'));
-
- $this->assertEquals(1, count($this->em->getRepository(__NAMESPACE__.'\Tag')->findAll()));
- }
-
- /**
- * @depends testReverseTransformNewUnknownEntity
- */
- public function testReverseTransformRemoveEntity()
- {
- $transformer = $this->createTransformer();
-
- $tags = $this->createTagCollection();
- $tags = $transformer->reverseTransform("foo", $tags);
-
- $this->assertEquals(1, count($tags));
- }
-
-}
-
-/** @Entity */
-class Tag
-{
- /** @Id @GeneratedValue @Column(type="integer") */
- public $id;
-
- /** @Column(type="string") */
- public $name;
-
- public function __construct($name) {
- $this->name = $name;
- }
-}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/CookieTest.php b/tests/Symfony/Tests/Component/HttpFoundation/CookieTest.php
new file mode 100644
index 0000000000000..7ab76a4c1291c
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/CookieTest.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpFoundation;
+
+use Symfony\Component\HttpFoundation\Cookie;
+
+/**
+ * CookieTest
+ *
+ * @author John Kary
+ */
+class CookieTest extends \PHPUnit_Framework_TestCase
+{
+ public function invalidNames()
+ {
+ return array(
+ array(''),
+ array(",MyName"),
+ array(";MyName"),
+ array(" MyName"),
+ array("\tMyName"),
+ array("\rMyName"),
+ array("\nMyName"),
+ array("\013MyName"),
+ array("\014MyName"),
+ );
+ }
+
+ public function invalidValues()
+ {
+ return array(
+ array(",MyValue"),
+ array(";MyValue"),
+ array(" MyValue"),
+ array("\tMyValue"),
+ array("\rMyValue"),
+ array("\nMyValue"),
+ array("\013MyValue"),
+ array("\014MyValue"),
+ );
+ }
+
+ /**
+ * @dataProvider invalidNames
+ * @expectedException InvalidArgumentException
+ * @covers Symfony\Component\HttpFoundation\Cookie::__construct
+ */
+ public function testInstantiationThrowsExceptionIfCookieNameContainsInvalidCharacters($name)
+ {
+ new Cookie($name);
+ }
+
+ /**
+ * @dataProvider invalidValues
+ * @expectedException InvalidArgumentException
+ * @covers Symfony\Component\HttpFoundation\Cookie::__construct
+ */
+ public function testInstantiationThrowsExceptionIfCookieValueContainsInvalidCharacters($value)
+ {
+ new Cookie('MyCookie', $value);
+ }
+
+ /**
+ * @covers Symfony\Component\HttpFoundation\Cookie::getValue
+ */
+ public function testGetValue()
+ {
+ $value = 'MyValue';
+ $cookie = new Cookie('MyCookie', $value);
+
+ $this->assertSame($value, $cookie->getValue(), '->getValue() returns the proper value');
+ }
+}
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/HttpFoundation/File/Fixtures/.unknownextension b/tests/Symfony/Tests/Component/HttpFoundation/File/Fixtures/.unknownextension
new file mode 100644
index 0000000000000..4d1ae35ba2c8e
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/File/Fixtures/.unknownextension
@@ -0,0 +1 @@
+f
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/File/MimeType/MimeTypeTest.php b/tests/Symfony/Tests/Component/HttpFoundation/File/MimeType/MimeTypeTest.php
new file mode 100644
index 0000000000000..957f2c0375e59
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/File/MimeType/MimeTypeTest.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpFoundation\File;
+
+use Symfony\Component\HttpFoundation\File\File;
+use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
+use Symfony\Component\HttpFoundation\File\MimeType\ContentTypeMimeTypeGuesser;
+use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
+use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
+use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
+
+class MimeTypeTest extends \PHPUnit_Framework_TestCase
+{
+ protected $path;
+
+ public function testGuessImageWithoutExtension()
+ {
+ $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
+ }
+
+ public function testGuessImageWithContentTypeMimeTypeGuesser()
+ {
+ $guesser = MimeTypeGuesser::getInstance();
+ $guesser->register(new ContentTypeMimeTypeGuesser());
+ $this->assertEquals('image/gif', $guesser->guess(__DIR__.'/../Fixtures/test'));
+ }
+
+ public function testGuessImageWithFileBinaryMimeTypeGuesser()
+ {
+ $guesser = MimeTypeGuesser::getInstance();
+ $guesser->register(new FileBinaryMimeTypeGuesser());
+ $this->assertEquals('image/gif', $guesser->guess(__DIR__.'/../Fixtures/test'));
+ }
+
+ public function testGuessImageWithKnownExtension()
+ {
+ $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif'));
+ }
+
+ public function testGuessFileWithUnknownExtension()
+ {
+ $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension'));
+ }
+
+ public function testGuessWithIncorrectPath()
+ {
+ $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
+ MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/not_here');
+ }
+
+ public function testGuessWithNonReadablePath()
+ {
+ $path = __DIR__.'/../Fixtures/to_delete';
+ touch($path);
+ chmod($path, 0333);
+
+ $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException');
+ MimeTypeGuesser::getInstance()->guess($path);
+ }
+
+ public static function tearDownAfterClass()
+ {
+ $path = __DIR__.'/../Fixtures/to_delete';
+ if (file_exists($path)) {
+ chmod($path, 0666);
+ @unlink($path);
+ }
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/File/UploadedFileTest.php b/tests/Symfony/Tests/Component/HttpFoundation/File/UploadedFileTest.php
index 5e5cb5d69677a..fe2fa432a4302 100644
--- a/tests/Symfony/Tests/Component/HttpFoundation/File/UploadedFileTest.php
+++ b/tests/Symfony/Tests/Component/HttpFoundation/File/UploadedFileTest.php
@@ -15,6 +15,7 @@
class UploadedFileTest extends \PHPUnit_Framework_TestCase
{
+
public function testFileUploadsMustBeEnabled()
{
// we can't change this setting without modifying php.ini :(
@@ -31,6 +32,42 @@ public function testFileUploadsMustBeEnabled()
}
}
+ public function testFileUploadsWithNoMimeType()
+ {
+ // we can't change this setting without modifying php.ini :(
+ if (ini_get('file_uploads')) {
+
+ $file = new UploadedFile(
+ __DIR__.'/Fixtures/test.gif',
+ 'original.gif',
+ null,
+ filesize(__DIR__.'/Fixtures/test.gif'),
+ UPLOAD_ERR_OK
+ );
+
+ $this->assertAttributeEquals('application/octet-stream', 'mimeType', $file);
+ $this->assertEquals('image/gif', $file->getMimeType());
+ }
+ }
+
+ public function testFileUploadsWithUnknownMimeType()
+ {
+ // we can't change this setting without modifying php.ini :(
+ if (ini_get('file_uploads')) {
+
+ $file = new UploadedFile(
+ __DIR__.'/Fixtures/.unknownextension',
+ 'original.gif',
+ null,
+ filesize(__DIR__.'/Fixtures/.unknownextension'),
+ UPLOAD_ERR_OK
+ );
+
+ $this->assertAttributeEquals('application/octet-stream', 'mimeType', $file);
+ $this->assertEquals('application/octet-stream', $file->getMimeType());
+ }
+ }
+
public function testErrorIsOkByDefault()
{
// we can't change this setting without modifying php.ini :(
@@ -46,4 +83,19 @@ public function testErrorIsOkByDefault()
$this->assertEquals(UPLOAD_ERR_OK, $file->getError());
}
}
+ public function testGetOriginalName()
+ {
+ // we can't change this setting without modifying php.ini :(
+ if (ini_get('file_uploads')) {
+ $file = new UploadedFile(
+ __DIR__.'/Fixtures/test.gif',
+ 'original.gif',
+ 'image/gif',
+ filesize(__DIR__.'/Fixtures/test.gif'),
+ null
+ );
+
+ $this->assertEquals('original.gif', $file->getOriginalName());
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
index 59be4968a83d1..467e7c8735ea7 100644
--- a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
+++ b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
@@ -54,28 +54,37 @@ public function testCreate()
$this->assertEquals('/foo', $request->getPathInfo());
$this->assertEquals('bar=baz', $request->getQueryString());
$this->assertEquals(80, $request->getPort());
+ $this->assertEquals('test.com', $request->getHttpHost());
+ $this->assertFalse($request->isSecure());
$request = Request::create('https://test.com/foo?bar=baz');
$this->assertEquals('https://test.com/foo?bar=baz', $request->getUri());
$this->assertEquals('/foo', $request->getPathInfo());
$this->assertEquals('bar=baz', $request->getQueryString());
$this->assertEquals(443, $request->getPort());
+ $this->assertEquals('test.com', $request->getHttpHost());
+ $this->assertTrue($request->isSecure());
$request = Request::create('test.com:90/foo');
$this->assertEquals('http://test.com:90/foo', $request->getUri());
$this->assertEquals('/foo', $request->getPathInfo());
$this->assertEquals('test.com', $request->getHost());
+ $this->assertEquals('test.com:90', $request->getHttpHost());
$this->assertEquals(90, $request->getPort());
+ $this->assertFalse($request->isSecure());
$request = Request::create('https://test.com:90/foo');
$this->assertEquals('https://test.com:90/foo', $request->getUri());
$this->assertEquals('/foo', $request->getPathInfo());
$this->assertEquals('test.com', $request->getHost());
+ $this->assertEquals('test.com:90', $request->getHttpHost());
$this->assertEquals(90, $request->getPort());
+ $this->assertTrue($request->isSecure());
$json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}';
$request = Request::create('http://example.com/jsonrpc', 'POST', array(), array(), array(), array(), $json);
$this->assertEquals($json, $request->getContent());
+ $this->assertFalse($request->isSecure());
}
/**
@@ -101,6 +110,7 @@ public function testDuplicate()
/**
* @covers Symfony\Component\HttpFoundation\Request::getFormat
+ * @covers Symfony\Component\HttpFoundation\Request::setFormat
* @dataProvider getFormatToMimeTypeMapProvider
*/
public function testGetFormatFromMimeType($format, $mimeTypes)
@@ -109,7 +119,10 @@ public function testGetFormatFromMimeType($format, $mimeTypes)
foreach ($mimeTypes as $mime) {
$this->assertEquals($format, $request->getFormat($mime));
}
-
+ $request->setFormat($format, $mimeTypes);
+ foreach ($mimeTypes as $mime) {
+ $this->assertEquals($format, $request->getFormat($mime));
+ }
}
/**
@@ -322,6 +335,7 @@ public function testGetUriForPath()
$request->initialize(array(), array(), array(), array(), array(), $server);
$this->assertEquals('http://hostname/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite, default port without HOST_HEADER');
+ $this->assertEquals('hostname', $request->getHttpHost());
}
/**
@@ -420,6 +434,23 @@ public function testGetSetMethod()
$this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
}
+ public function testGetClientIp()
+ {
+ $request = new Request;
+ $this->assertEquals('', $request->getClientIp());
+ $this->assertEquals('', $request->getClientIp(true));
+ $request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '88.88.88.88'));
+ $this->assertEquals('88.88.88.88', $request->getClientIp());
+ $request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_CLIENT_IP' => '88.88.88.88'));
+ $this->assertEquals('127.0.0.1', $request->getClientIp());
+ $request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_CLIENT_IP' => '88.88.88.88'));
+ $this->assertEquals('88.88.88.88', $request->getClientIp(true));
+ $request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_X_FORWARDED_FOR' => '88.88.88.88'));
+ $this->assertEquals('127.0.0.1', $request->getClientIp());
+ $request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_X_FORWARDED_FOR' => '88.88.88.88'));
+ $this->assertEquals('88.88.88.88', $request->getClientIp(true));
+ }
+
public function testGetContentWorksTwiceInDefaultMode()
{
$req = new Request;
@@ -473,4 +504,163 @@ public function testCreateFromGlobals()
unset($_GET['foo1'], $_POST['foo2'], $_COOKIE['foo3'], $_FILES['foo4'], $_SERVER['foo5']);
}
+
+ public function testOverrideGlobals()
+ {
+ $time = $_SERVER['REQUEST_TIME']; // fix for phpunit timer
+
+ $request = new Request();
+ $request->initialize(array('foo' => 'bar'));
+ $request->overrideGlobals();
+
+ $this->assertEquals(array('foo' => 'bar'), $_GET);
+
+ $request->initialize(array(), array('foo' => 'bar'));
+ $request->overrideGlobals();
+
+ $this->assertEquals(array('foo' => 'bar'), $_POST);
+
+ $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
+
+ $request->headers->set('X_FORWARDED_PROTO', 'https');
+
+ $this->assertTrue($request->isSecure());
+
+ $request->overrideGlobals();
+
+ $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
+
+ $_SERVER['REQUEST_TIME'] = $time; // fix for phpunit timer
+ }
+
+ public function testGetScriptName()
+ {
+ $request = new Request();
+ $this->assertEquals('', $request->getScriptName());
+
+ $server = array();
+ $server['SCRIPT_NAME'] = '/index.php';
+
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('/index.php', $request->getScriptName());
+
+ $server = array();
+ $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('/frontend.php', $request->getScriptName());
+
+ $server = array();
+ $server['SCRIPT_NAME'] = '/index.php';
+ $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('/index.php', $request->getScriptName());
+ }
+
+ public function testGetBasePath()
+ {
+ $request = new Request();
+ $this->assertEquals('', $request->getBasePath());
+
+ $server = array();
+ $server['SCRIPT_FILENAME'] = '/some/where/index.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+ $this->assertEquals('', $request->getBasePath());
+
+ $server = array();
+ $server['SCRIPT_FILENAME'] = '/some/where/index.php';
+ $server['SCRIPT_NAME'] = '/index.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('', $request->getBasePath());
+
+ $server = array();
+ $server['SCRIPT_FILENAME'] = '/some/where/index.php';
+ $server['PHP_SELF'] = '/index.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('', $request->getBasePath());
+
+ $server = array();
+ $server['SCRIPT_FILENAME'] = '/some/where/index.php';
+ $server['ORIG_SCRIPT_NAME'] = '/index.php';
+ $request->initialize(array(), array(), array(), array(), array(), $server);
+
+ $this->assertEquals('', $request->getBasePath());
+ }
+
+ public function testGetPreferredLanguage()
+ {
+ $request = new Request();
+ $this->assertEquals('', $request->getPreferredLanguage());
+ $this->assertEquals('fr', $request->getPreferredLanguage(array('fr')));
+ $this->assertEquals('fr', $request->getPreferredLanguage(array('fr', 'en')));
+ $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'fr')));
+ $this->assertEquals('fr-ch', $request->getPreferredLanguage(array('fr-ch', 'fr-fr')));
+
+ $request = new Request();
+ $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
+ $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'en-us')));
+
+ $request = new Request();
+ $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
+ $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
+ }
+
+ public function testIsXmlHttpRequest()
+ {
+ $request = new Request();
+ $this->assertFalse($request->isXmlHttpRequest());
+
+ $request->headers->set('X-Requested-With', 'XMLHttpRequest');
+ $this->assertTrue($request->isXmlHttpRequest());
+
+ $request->headers->remove('X-Requested-With');
+ $this->assertFalse($request->isXmlHttpRequest());
+ }
+
+ public function testGetCharsets()
+ {
+ $request = new Request();
+ $this->assertEquals(array(), $request->getCharsets());
+ $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
+ $this->assertEquals(array(), $request->getCharsets()); // testing caching
+
+ $request = new Request();
+ $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
+ $this->assertEquals(array('ISO-8859-1', 'US-ASCII', 'UTF-8', 'ISO-10646-UCS-2'), $request->getCharsets());
+
+ $request = new Request();
+ $request->headers->set('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7');
+ $this->assertEquals(array('ISO-8859-1', '*', 'utf-8'), $request->getCharsets());
+ }
+
+ public function testGetAcceptableContentTypes()
+ {
+ $request = new Request();
+ $this->assertEquals(array(), $request->getAcceptableContentTypes());
+ $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
+ $this->assertEquals(array(), $request->getAcceptableContentTypes()); // testing caching
+
+ $request = new Request();
+ $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
+ $this->assertEquals(array('multipart/mixed', '*/*', 'text/html', 'application/xhtml+xml', 'text/vnd.wap.wml', 'application/vnd.wap.xhtml+xml', 'application/vnd.wap.wmlscriptc'), $request->getAcceptableContentTypes());
+ }
+
+ public function testGetLanguages()
+ {
+ $request = new Request();
+ $this->assertNull($request->getLanguages());
+
+ $request = new Request();
+ $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
+ $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
+ $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
+
+ $request = new Request();
+ $request->headers->set('Accept-language', 'zh, i-cherokee; q=0.6');
+ $this->assertEquals(array('zh', 'cherokee'), $request->getLanguages());
+ }
}
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/HttpCache/HttpCacheTest.php b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTest.php
index 4c0d7cfde9e42..d6a5ba7f2afaf 100644
--- a/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTest.php
+++ b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTest.php
@@ -893,4 +893,67 @@ public function testShouldNotCatchExceptions()
$this->assertExceptionsAreNotCaught();
}
+
+ public function testEsiCacheSendsTheLowestTtl()
+ {
+ $responses = array(
+ array(
+ 'status' => 200,
+ 'body' => ' ',
+ 'headers' => array(
+ 'Cache-Control' => 's-maxage=300',
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ ),
+ ),
+ array(
+ 'status' => 200,
+ 'body' => 'Hello World!',
+ 'headers' => array('Cache-Control' => 's-maxage=300'),
+ ),
+ array(
+ 'status' => 200,
+ 'body' => 'My name is Bobby.',
+ 'headers' => array('Cache-Control' => 's-maxage=100'),
+ ),
+ );
+
+ $this->setNextResponses($responses);
+
+ $this->request('GET', '/', array(), array(), true);
+ $this->assertEquals("Hello World! My name is Bobby.", $this->response->getContent());
+ $this->assertEquals(100, $this->response->getTtl());
+ }
+
+ public function testEsiCacheForceValidation()
+ {
+ $responses = array(
+ array(
+ 'status' => 200,
+ 'body' => ' ',
+ 'headers' => array(
+ 'Cache-Control' => 's-maxage=300',
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ ),
+ ),
+ array(
+ 'status' => 200,
+ 'body' => 'Hello World!',
+ 'headers' => array('ETag' => 'foobar'),
+ ),
+ array(
+ 'status' => 200,
+ 'body' => 'My name is Bobby.',
+ 'headers' => array('Cache-Control' => 's-maxage=100'),
+ ),
+ );
+
+ $this->setNextResponses($responses);
+
+ $this->request('GET', '/', array(), array(), true);
+ $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());
+ $this->assertEquals(null, $this->response->getTtl());
+ $this->assertTrue($this->response->mustRevalidate());
+ $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));
+ $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));
+ }
}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTestCase.php b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTestCase.php
index 1af5811cc1808..a7654a5e162f5 100644
--- a/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTestCase.php
+++ b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/HttpCacheTestCase.php
@@ -12,8 +12,10 @@
namespace Symfony\Tests\Component\HttpKernel\HttpCache;
require_once __DIR__.'/TestHttpKernel.php';
+require_once __DIR__.'/TestMultipleHttpKernel.php';
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -28,12 +30,14 @@ class HttpCacheTestCase extends \PHPUnit_Framework_TestCase
protected $response;
protected $responses;
protected $catch;
+ protected $esi;
protected function setUp()
{
$this->kernel = null;
$this->cache = null;
+ $this->esi = null;
$this->caches = array();
$this->cacheConfig = array();
@@ -41,6 +45,7 @@ protected function setUp()
$this->response = null;
$this->responses = array();
+
$this->catch = false;
$this->clearDirectory(sys_get_temp_dir().'/http_cache');
@@ -101,7 +106,7 @@ public function assertExceptionsAreNotCaught()
$this->assertFalse($this->kernel->isCatchingExceptions());
}
- public function request($method, $uri = '/', $server = array(), $cookies = array())
+ public function request($method, $uri = '/', $server = array(), $cookies = array(), $esi = false)
{
if (null === $this->kernel) {
throw new \LogicException('You must call setNextResponse() before calling request().');
@@ -112,7 +117,9 @@ public function request($method, $uri = '/', $server = array(), $cookies = array
$this->store = new Store(sys_get_temp_dir().'/http_cache');
$this->cacheConfig['debug'] = true;
- $this->cache = new HttpCache($this->kernel, $this->store, null, $this->cacheConfig);
+
+ $this->esi = $esi ? new Esi() : null;
+ $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig);
$this->request = Request::create($uri, $method, array(), $cookies, array(), $server);
$this->response = $this->cache->handle($this->request, HttpKernelInterface::MASTER_REQUEST, $this->catch);
@@ -133,11 +140,14 @@ public function getMetaStorageValues()
// A basic response with 200 status code and a tiny body.
public function setNextResponse($statusCode = 200, array $headers = array(), $body = 'Hello World', \Closure $customizer = null)
{
- $called = false;
-
$this->kernel = new TestHttpKernel($body, $statusCode, $headers, $customizer);
}
+ public function setNextResponses($responses)
+ {
+ $this->kernel = new TestMultipleHttpKernel($responses);
+ }
+
public function catchExceptions($catch = true)
{
$this->catch = $catch;
diff --git a/tests/Symfony/Tests/Component/HttpKernel/HttpCache/TestMultipleHttpKernel.php b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/TestMultipleHttpKernel.php
new file mode 100644
index 0000000000000..899e8c2b57dd7
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpKernel/HttpCache/TestMultipleHttpKernel.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpKernel\HttpCache;
+
+use Symfony\Component\HttpKernel\HttpKernel;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
+
+class TestMultipleHttpKernel extends HttpKernel implements ControllerResolverInterface
+{
+ protected $bodies;
+ protected $statuses;
+ protected $headers;
+ protected $catch;
+ protected $call;
+
+ public function __construct($responses)
+ {
+ $this->bodies = array();
+ $this->statuses = array();
+ $this->headers = array();
+ $this->call = false;
+
+ foreach ($responses as $response) {
+ $this->bodies[] = $response['body'];
+ $this->statuses[] = $response['status'];
+ $this->headers[] = $response['headers'];
+ }
+
+ parent::__construct(new EventDispatcher(), $this);
+ }
+
+ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false)
+ {
+ return parent::handle($request, $type, $catch);
+ }
+
+ public function getController(Request $request)
+ {
+ return array($this, 'callController');
+ }
+
+ public function getArguments(Request $request, $controller)
+ {
+ return array($request);
+ }
+
+ public function callController(Request $request)
+ {
+ $this->called = true;
+
+ $response = new Response(array_shift($this->bodies), array_shift($this->statuses), array_shift($this->headers));
+
+ return $response;
+ }
+
+ public function hasBeenCalled()
+ {
+ return $this->called;
+ }
+
+ public function reset()
+ {
+ $this->call = false;
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php b/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
index 5695f5a6fdbaf..18542f50f7a30 100644
--- a/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
+++ b/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php
@@ -13,10 +13,296 @@
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\Loader\LoaderInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
class KernelTest extends \PHPUnit_Framework_TestCase
+{
+ public function testConstructor()
+ {
+ $env = 'test_env';
+ $debug = true;
+ $kernel = new KernelForTest($env, $debug);
+
+ $this->assertEquals($env, $kernel->getEnvironment());
+ $this->assertEquals($debug, $kernel->isDebug());
+ $this->assertFalse($kernel->isBooted());
+ $this->assertLessThanOrEqual(microtime(true), $kernel->getStartTime());
+ $this->assertNull($kernel->getContainer());
+ }
+
+ public function testClone()
+ {
+ $env = 'test_env';
+ $debug = true;
+ $kernel = new KernelForTest($env, $debug);
+
+ $clone = clone $kernel;
+
+ $this->assertEquals($env, $clone->getEnvironment());
+ $this->assertEquals($debug, $clone->isDebug());
+ $this->assertFalse($clone->isBooted());
+ $this->assertLessThanOrEqual(microtime(true), $clone->getStartTime());
+ $this->assertNull($clone->getContainer());
+ }
+
+ public function testBootInitializesBundlesAndContainer()
+ {
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('initializeBundles', 'initializeContainer', 'getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('initializeBundles');
+ $kernel->expects($this->once())
+ ->method('initializeContainer');
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array()));
+
+ $kernel->boot();
+ }
+
+ public function testBootSetsTheContainerToTheBundles()
+ {
+ $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $bundle->expects($this->once())
+ ->method('setContainer');
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('initializeBundles', 'initializeContainer', 'getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array($bundle)));
+
+ $kernel->boot();
+ }
+
+ public function testBootSetsTheBootedFlagToTrue()
+ {
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('initializeBundles', 'initializeContainer', 'getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array()));
+
+ $kernel->boot();
+
+ $this->assertTrue($kernel->isBooted());
+ }
+
+ public function testBootKernelSeveralTimesOnlyInitializesBundlesOnce()
+ {
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('initializeBundles', 'initializeContainer', 'getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array()));
+
+ $kernel->boot();
+ $kernel->boot();
+ }
+
+ public function testShutdownCallsShutdownOnAllBundles()
+ {
+ $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $bundle->expects($this->once())
+ ->method('shutdown');
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array($bundle)));
+
+ $kernel->shutdown();
+ }
+
+ public function testShutdownGivesNullContainerToAllBundles()
+ {
+ $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $bundle->expects($this->once())
+ ->method('setContainer')
+ ->with(null);
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array($bundle)));
+
+ $kernel->shutdown();
+ }
+
+ public function testHandleCallsHandleOnHttpKernel()
+ {
+ $type = HttpKernelInterface::MASTER_REQUEST;
+ $catch = true;
+ $request = new Request();
+
+ $httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $httpKernelMock
+ ->expects($this->once())
+ ->method('handle')
+ ->with($request, $type, $catch);
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getHttpKernel'))
+ ->getMock();
+
+ $kernel->expects($this->once())
+ ->method('getHttpKernel')
+ ->will($this->returnValue($httpKernelMock));
+
+ $kernel->handle($request, $type, $catch);
+ }
+
+ public function testHandleBootsTheKernel()
+ {
+ $type = HttpKernelInterface::MASTER_REQUEST;
+ $catch = true;
+ $request = new Request();
+
+ $httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getHttpKernel', 'boot'))
+ ->getMock();
+
+ $kernel->expects($this->once())
+ ->method('getHttpKernel')
+ ->will($this->returnValue($httpKernelMock));
+
+ $kernel->expects($this->once())
+ ->method('boot');
+
+ // required as this value is initialized
+ // in the kernel constructor, which we don't call
+ $kernel->setIsBooted(false);
+
+ $kernel->handle($request, $type, $catch);
+ }
+
+ public function testStripComments()
+ {
+ if (!function_exists('token_get_all')) {
+ $this->markTestSkipped();
+ return;
+ }
+ $source = <<assertEquals($expected, Kernel::stripComments($source));
+ }
+
+ public function testIsClassInActiveBundleFalse()
+ {
+ $kernel = $this->getKernelMockForIsClassInActiveBundleTest();
+
+ $this->assertFalse($kernel->isClassInActiveBundle('Not\In\Active\Bundle'));
+ }
+
+ public function testIsClassInActiveBundleFalseNoNamespace()
+ {
+ $kernel = $this->getKernelMockForIsClassInActiveBundleTest();
+
+ $this->assertFalse($kernel->isClassInActiveBundle('NotNamespacedClass'));
+ }
+
+ public function testIsClassInActiveBundleTrue()
+ {
+ $kernel = $this->getKernelMockForIsClassInActiveBundleTest();
+
+ $this->assertTrue($kernel->isClassInActiveBundle(__NAMESPACE__.'\FooBarBundle\SomeClass'));
+ }
+
+ protected function getKernelMockForIsClassInActiveBundleTest()
+ {
+ $bundle = new FooBarBundle();
+
+ $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getBundles'))
+ ->getMock();
+ $kernel->expects($this->once())
+ ->method('getBundles')
+ ->will($this->returnValue(array($bundle)));
+
+ return $kernel;
+ }
+
+ public function testGetRootDir()
+ {
+ $kernel = new KernelForTest('test', true);
+
+ $this->assertEquals(__DIR__, $kernel->getRootDir());
+ }
+
+ public function testGetName()
+ {
+ $kernel = new KernelForTest('test', true);
+
+ $this->assertEquals('HttpKernel', $kernel->getName());
+ }
+
+ public function testSerialize()
+ {
+ $env = 'test_env';
+ $debug = true;
+ $kernel = new KernelForTest($env, $debug);
+
+ $expected = serialize(array($env, $debug));
+ $this->assertEquals($expected, $kernel->serialize());
+ }
+
/**
* @expectedException \InvalidArgumentException
*/
@@ -241,21 +527,21 @@ public function testInitializeBundleThrowsExceptionWhenRegisteringTwoBundlesWith
{
$fooBundle = $this->getBundle(null, null, 'FooBundle', 'DuplicateName');
$barBundle = $this->getBundle(null, null, 'BarBundle', 'DuplicateName');
-
+
$kernel = $this->getKernel();
$kernel
->expects($this->once())
->method('registerBundles')
->will($this->returnValue(array($fooBundle, $barBundle)))
;
- $kernel->initializeBundles();
+ $kernel->initializeBundles();
}
protected function getBundle($dir = null, $parent = null, $className = null, $bundleName = null)
{
$bundle = $this
->getMockBuilder('Symfony\Tests\Component\HttpKernel\BundleForTest')
- ->setMethods(array('getNormalizedPath', 'getParent', 'getName'))
+ ->setMethods(array('getPath', 'getParent', 'getName'))
->disableOriginalConstructor()
;
@@ -273,16 +559,16 @@ protected function getBundle($dir = null, $parent = null, $className = null, $bu
$bundle
->expects($this->any())
- ->method('getNormalizedPath')
+ ->method('getPath')
->will($this->returnValue(strtr($dir, '\\', '/')))
;
-
+
$bundle
->expects($this->any())
->method('getParent')
->will($this->returnValue($parent))
;
-
+
return $bundle;
}
@@ -315,6 +601,7 @@ public function getBundleMap()
public function registerRootDir()
{
+ return __DIR__;
}
public function registerBundles()
@@ -333,9 +620,24 @@ public function initializeBundles()
{
parent::initializeBundles();
}
+
+ public function isBooted()
+ {
+ return $this->booted;
+ }
+
+ public function setIsBooted($value)
+ {
+ $this->booted = (bool) $value;
+ }
}
abstract class BundleForTest implements BundleInterface
{
// We can not extend Symfony\Component\HttpKernel\Bundle\Bundle as we want to mock getName() which is final
-}
\ No newline at end of file
+}
+
+class FooBarBundle extends Bundle
+{
+ // We need a full namespaced bundle instance to test isClassInActiveBundle
+}