diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 6b2f7c9688699..a2e485f0c0a21 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -12,6 +12,7 @@ Symfony\Component\Routing\Loader\XmlFileLoader Symfony\Component\Routing\Loader\YamlFileLoader Symfony\Component\Routing\Loader\PhpFileLoader + Symfony\Component\Routing\Loader\DirectoryLoader Symfony\Component\Routing\Generator\UrlGenerator Symfony\Component\Routing\Generator\UrlGenerator Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper @@ -45,6 +46,11 @@ + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index dce63a74b99cb..349253e007fcb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.3.9", - "symfony/dependency-injection" : "~2.6,>=2.6.2", + "symfony/dependency-injection" : "~2.7,>=2.6.2", "symfony/config" : "~2.4", "symfony/event-dispatcher": "~2.5|~3.0.0", "symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4|~3.0.0", diff --git a/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php b/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php new file mode 100644 index 0000000000000..48bf2fb1b913d --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Loader/DirectoryLoader.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader; + +use Symfony\Component\Config\Resource\DirectoryResource; + +/** + * DirectoryLoader is a recursive loader to go through directories + * + * @author Sebastien Lavoie + */ +class DirectoryLoader extends FileLoader +{ + /** + * {@inheritdoc} + */ + public function load($file, $type = null) + { + $file = rtrim($file, '/'); + $path = $this->locator->locate($file); + $this->container->addResource(new DirectoryResource($path)); + + foreach (scandir($path) as $dir) { + if ($dir[0] !== '.') { + if (is_dir($path.'/'.$dir)) { + $dir .= '/'; // append / to allow recursion + } + + $this->setCurrentDir($path); + + $this->import($dir, null, false, $path); + } + } + } + + /** + * {@inheritdoc} + */ + public function supports($resource, $type = null) + { + if ('directory' === $type) { + return true; + } + + if (null === $type) { + return preg_match('/\/$/', $resource) === 1; + } + + return false; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/import/import.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/import/import.yml new file mode 100644 index 0000000000000..35ec4a0427136 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/import/import.yml @@ -0,0 +1,2 @@ +imports: + - { resource: ../recurse/ } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.ini b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.ini new file mode 100644 index 0000000000000..0984cdac770a4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.ini @@ -0,0 +1,2 @@ +[parameters] + ini = ini diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.yml new file mode 100644 index 0000000000000..f98ef12ea3c65 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/recurse/simple.yml @@ -0,0 +1,2 @@ +parameters: + yaml: yaml diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/simple.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/simple.php new file mode 100644 index 0000000000000..4750324ad1de3 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/directory/simple.php @@ -0,0 +1,3 @@ +setParameter('php', 'php'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/DirectoryLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/DirectoryLoaderTest.php new file mode 100644 index 0000000000000..c19c5de3a57df --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/DirectoryLoaderTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Loader; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; +use Symfony\Component\DependencyInjection\Loader\IniFileLoader; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; +use Symfony\Component\Config\Loader\LoaderResolver; +use Symfony\Component\Config\FileLocator; + +class DirectoryLoaderTest extends \PHPUnit_Framework_TestCase +{ + private static $fixturesPath; + + private $container; + private $loader; + + public static function setUpBeforeClass() + { + self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); + } + + protected function setUp() + { + $locator = new FileLocator(self::$fixturesPath); + $this->container = new ContainerBuilder(); + $this->loader = new DirectoryLoader($this->container, $locator); + $resolver = new LoaderResolver(array( + new PhpFileLoader($this->container, $locator), + new IniFileLoader($this->container, $locator), + new YamlFileLoader($this->container, $locator), + $this->loader, + )); + $this->loader->setResolver($resolver); + } + + public function testDirectoryCanBeLoadedRecursively() + { + $this->loader->load('directory/'); + $this->assertEquals(array('ini' => 'ini', 'yaml' => 'yaml', 'php' => 'php'), $this->container->getParameterBag()->all(), '->load() takes a single directory'); + } + + public function testImports() + { + $this->loader->resolve('directory/import/import.yml')->load('directory/import/import.yml'); + $this->assertEquals(array('ini' => 'ini', 'yaml' => 'yaml'), $this->container->getParameterBag()->all(), '->load() takes a single file that imports a directory'); + } + + /** + * @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::__construct + * @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::load + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The file "foo" does not exist (in: + */ + public function testExceptionIsRaisedWhenDirectoryDoesNotExist() + { + $this->loader->load('foo/'); + } + + /** + * @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::supports + */ + public function testSupports() + { + $loader = new DirectoryLoader(new ContainerBuilder(), new FileLocator()); + + $this->assertTrue($loader->supports('directory/'), '->supports("directory/") returns true'); + $this->assertTrue($loader->supports('directory/', 'directory'), '->supports("directory/", "directory") returns true'); + $this->assertFalse($loader->supports('directory'), '->supports("directory") returns false'); + $this->assertTrue($loader->supports('directory', 'directory'), '->supports("directory", "directory") returns true'); + $this->assertFalse($loader->supports('directory', 'foo'), '->supports("directory, "foo") returns false'); + } +} diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b9ecd71abe63c..ae36380bbea34 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; +use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -251,7 +252,7 @@ public function getBundle($name, $first = true) } /** - * {@inheritDoc} + * {@inheritdoc} * * @throws \RuntimeException if a custom resource is hidden by a resource in a derived bundle */ @@ -716,6 +717,7 @@ protected function getContainerLoader(ContainerInterface $container) new YamlFileLoader($container, $locator), new IniFileLoader($container, $locator), new PhpFileLoader($container, $locator), + new DirectoryLoader($container, $locator), new ClosureLoader($container), )); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index de1e9d2277b2e..d2969ba1aefc8 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -33,7 +33,7 @@ "symfony/expression-language": "~2.4|~3.0.0", "symfony/finder": "~2.0,>=2.0.5|~3.0.0", "symfony/process": "~2.0,>=2.0.5|~3.0.0", - "symfony/routing": "~2.2|~3.0.0", + "symfony/routing": "~2.7|~3.0.0", "symfony/stopwatch": "~2.3|~3.0.0", "symfony/templating": "~2.2|~3.0.0", "symfony/translation": "~2.0,>=2.0.5|~3.0.0", diff --git a/src/Symfony/Component/Routing/Loader/DirectoryLoader.php b/src/Symfony/Component/Routing/Loader/DirectoryLoader.php new file mode 100644 index 0000000000000..92041090e5543 --- /dev/null +++ b/src/Symfony/Component/Routing/Loader/DirectoryLoader.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Routing\Loader; + +use Symfony\Component\Config\Loader\FileLoader; +use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Config\Resource\DirectoryResource; + +class DirectoryLoader extends FileLoader +{ + /** + * {@inheritdoc} + */ + public function load($file, $type = null) + { + $path = $this->locator->locate($file); + + $collection = new RouteCollection(); + $collection->addResource(new DirectoryResource($path)); + + foreach (scandir($path) as $dir) { + if ($dir[0] !== '.') { + $this->setCurrentDir($path); + $subPath = $path.'/'.$dir; + $subType = null; + + if (is_dir($subPath)) { + $subPath .= '/'; + $subType = 'directory'; + } + + $subCollection = $this->import($subPath, $subType, false, $path); + $collection->addCollection($subCollection); + } + } + + return $collection; + } + + /** + * {@inheritdoc} + */ + public function supports($resource, $type = null) + { + // only when type is forced to directory, not to conflict with AnnotationLoader + + return 'directory' === $type; + } +} diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes1.yml b/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes1.yml new file mode 100644 index 0000000000000..d078836625c6b --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes1.yml @@ -0,0 +1,2 @@ +route1: + path: /route/1 diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes2.yml b/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes2.yml new file mode 100644 index 0000000000000..938fb2457e9a3 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/directory/recurse/routes2.yml @@ -0,0 +1,2 @@ +route2: + path: /route/2 diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/directory/routes3.yml b/src/Symfony/Component/Routing/Tests/Fixtures/directory/routes3.yml new file mode 100644 index 0000000000000..088cfb4d4315e --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/directory/routes3.yml @@ -0,0 +1,2 @@ +route3: + path: /route/3 diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/directory_import/import.yml b/src/Symfony/Component/Routing/Tests/Fixtures/directory_import/import.yml new file mode 100644 index 0000000000000..af829e58c7ffd --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/directory_import/import.yml @@ -0,0 +1,3 @@ +_directory: + resource: "../directory" + type: directory diff --git a/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php new file mode 100644 index 0000000000000..101b5093a2fff --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Routing\Tests\Loader; + +use Symfony\Component\Routing\Loader\DirectoryLoader; +use Symfony\Component\Routing\Loader\YamlFileLoader; +use Symfony\Component\Routing\Loader\AnnotationFileLoader; +use Symfony\Component\Config\Loader\LoaderResolver; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Routing\RouteCollection; + +class DirectoryLoaderTest extends AbstractAnnotationLoaderTest +{ + private $loader; + private $reader; + + protected function setUp() + { + parent::setUp(); + + $locator = new FileLocator(); + $this->reader = $this->getReader(); + $this->loader = new DirectoryLoader($locator); + $resolver = new LoaderResolver(array( + new YamlFileLoader($locator), + new AnnotationFileLoader($locator, $this->getClassLoader($this->reader)), + $this->loader, + )); + $this->loader->setResolver($resolver); + } + + public function testLoadDirectory() + { + $collection = $this->loader->load(__DIR__.'/../Fixtures/directory', 'directory'); + $this->verifyCollection($collection); + } + + public function testImportDirectory() + { + $collection = $this->loader->load(__DIR__.'/../Fixtures/directory_import', 'directory'); + $this->verifyCollection($collection); + } + + private function verifyCollection(RouteCollection $collection) + { + $routes = $collection->all(); + + $this->assertCount(3, $routes, 'Three routes are loaded'); + $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); + + for ($i = 1; $i <= 3; $i++) { + $this->assertSame('/route/'.$i, $routes["route".$i]->getPath()); + } + } + + public function testSupports() + { + $fixturesDir = __DIR__.'/../Fixtures'; + + $this->assertFalse($this->loader->supports($fixturesDir), '->supports(*) returns false'); + + $this->assertTrue($this->loader->supports($fixturesDir, 'directory'), '->supports(*, "directory") returns true'); + $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports(*, "foo") returns false'); + } +}