8000 [DI][Routing] recursive directory loading · symfony/symfony@73f0ee2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 73f0ee2

Browse files
lavoieslnicolas-grekas
authored andcommitted
[DI][Routing] recursive directory loading
Issue #11045 For now, the Routing DirectoryLoader requires the type `directory` to be specified so it does not conflict with `AnnotationDirectoryLoader`. However, this could be refactored.
1 parent 78cf382 commit 73f0ee2

File tree

16 files changed

+305
-2
lines changed

16 files changed

+305
-2
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<parameter key="routing.loader.xml.class">Symfony\Component\Routing\Loader\XmlFileLoader</parameter>
1313
<parameter key="routing.loader.yml.class">Symfony\Component\Routing\Loader\YamlFileLoader</parameter>
1414
<parameter key="routing.loader.php.class">Symfony\Component\Routing\Loader\PhpFileLoader</parameter>
15+
<parameter key="routing.loader.directory.class">Symfony\Component\Routing\Loader\DirectoryLoader</parameter>
1516
<parameter key="router.options.generator_class">Symfony\Component\Routing\Generator\UrlGenerator</parameter>
1617
<parameter key="router.options.generator_base_class">Symfony\Component\Routing\Generator\UrlGenerator</parameter>
1718
<parameter key="router.options.generator_dumper_class">Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper</parameter>
@@ -45,6 +46,11 @@
4546
<argument type="service" id="file_locator" />
4647
</service>
4748

49+
<service id="routing.loader.directory" class="%routing.loader.directory.class%" public="false">
50+
<tag name="routing.loader" />
51+
<argument type="service" id="file_locator" />
52+
</service>
53+
4854
<service id="routing.loader" class="%routing.loader.class%">
4955
<tag name="monolog.logger" channel="router" />
5056
<argument type="service" id="controller_name_converter" />

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"require": {
1919
"php": ">=5.3.9",
2020
"symfony/asset": "~2.7|~3.0.0",
21-
"symfony/dependency-injection" : "~2.6,>=2.6.2",
21+
"symfony/dependency-injection" : "~2.8",
2222
"symfony/config" : "~2.4",
2323
"symfony/event-dispatcher": "~2.5|~3.0.0",
2424
"symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4|~3.0.0",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Loader;
13+
14+
use Symfony\Component\Config\Resource\DirectoryResource;
15+
16+
/**
17+
* DirectoryLoader is a recursive loader to go through directories
18+
*
19+
* @author Sebastien Lavoie <seb@wemakecustom.com>
20+
*/
21+
class DirectoryLoader extends FileLoader
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function load($file, $type = null)
27+
{
28+
$file = rtrim($file, '/');
29+
$path = $this->locator->locate($file);
30+
$this->container->addResource(new DirectoryResource($path));
31+
32+
foreach (scandir($path) as $dir) {
33+
if ($dir[0] !== '.') {
34+
if (is_dir($path.'/'.$dir)) {
35+
$dir .= '/'; // append / to allow recursion
36+
}
37+
38+
$this->setCurrentDir($path);
39+
40+
$this->import($dir, null, false, $path);
41+
}
42+
}
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
*/
48+
public function supports($resource, $type = null)
49+
{
50+
if ('directory' === $type) {
51+
return true;
52+
}
53+
54+
if (null === $type) {
55+
return preg_match('/\/$/', $resource) === 1;
56+
}
57+
58+
return false;
59+
}
60+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports:
2+
- { resource: ../recurse/ }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[parameters]
2+
ini = ini
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
parameters:
2+
yaml: yaml
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
$container->setParameter('php', 'php');
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Loader;
13+
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
16+
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
17+
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
18+
use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
19+
use Symfony\Component\Config\Loader\LoaderResolver;
20+
use Symfony\Component\Config\FileLocator;
21+
22+
class DirectoryLoaderTest extends \PHPUnit_Framework_TestCase
23+
{
24+
private static $fixturesPath;
25+
26+
private $container;
27+
private $loader;
28+
29+
public static function setUpBeforeClass()
30+
{
31+
self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
32+
}
33+
34+
protected function setUp()
35+
{
36+
$locator = new FileLocator(self::$fixturesPath);
37+
$this->container = new ContainerBuilder();
38+
$this->loader = new DirectoryLoader($this->container, $locator);
39+
$resolver = new LoaderResolver(array(
40+
new PhpFileLoader($this->container, $locator),
41+
new IniFileLoader($this->container, $locator),
42+
new YamlFileLoader($this->container, $locator),
43+
$this->loader,
44+
));
45+
$this->loader->setResolver($resolver);
46+
}
47+
48+
public function testDirectoryCanBeLoadedRecursively()
49+
{
50+
$this->loader->load('directory/');
51+
$this->assertEquals(array('ini' => 'ini', 'yaml' => 'yaml', 'php' => 'php'), $this->container->getParameterBag()->all(), '->load() takes a single directory');
52+
}
53+
54+
public function testImports()
55+
{
56+
$this->loader->resolve('directory/import/import.yml')->load('directory/import/import.yml');
57+
$this->assertEquals(array('ini' => 'ini', 'yaml' => 'yaml'), $this->container->getParameterBag()->all(), '->load() takes a single file that imports a directory');
58+
}
59+
60+
/**
61+
* @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::__construct
62+
* @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::load
63+
*
64+
* @expectedException \InvalidArgumentException
65+
* @expectedExceptionMessage The file "foo" does not exist (in:
66+
*/
67+
public function testExceptionIsRaisedWhenDirectoryDoesNotExist()
68+
{
69+
$this->loader->load('foo/');
70+
}
71+
72+
/**
73+
* @covers Symfony\Component\DependencyInjection\Loader\DirectoryLoader::supports
74+
*/
75+
public function testSupports()
76+
{
77+
$loader = new DirectoryLoader(new ContainerBuilder(), new FileLocator());
78+
79+
$this->assertTrue($loader->supports('directory/'), '->supports("directory/") returns true');
80+
$this->assertTrue($loader->supports('directory/', 'directory'), '->supports("directory/", "directory") returns true');
81+
$this->assertFalse($loader->supports('directory'), '->supports("directory") returns false');
82+
$this->assertTrue($loader->supports('directory', 'directory'), '->supports("directory", "directory") returns true');
83+
$this->assertFalse($loader->supports('directory', 'foo'), '->supports("directory, "foo") returns false');
84+
}
85+
}

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
2222
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2323
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
24+
use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
2425
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
2526
use Symfony\Component\HttpFoundation\Request;
2627
use Symfony\Component\HttpFoundation\Response;
@@ -721,6 +722,7 @@ protected function getContainerLoader(ContainerInterface $container)
721722
new YamlFileLoader($container, $locator),
722723
new IniFileLoader($container, $locator),
723724
new PhpFileLoader($container, $locator),
725+
new DirectoryLoader($container, $locator),
724726
new ClosureLoader($container),
725727
));
726728

src/Symfony/Component/HttpKernel/composer.json

Lines changed: 1 addition & 1 deletion
"symfony/templating": "~2.2|~3.0.0",
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"symfony/expression-language": "~2.4|~3.0.0",
3535
"symfony/finder": "~2.0,>=2.0.5|~3.0.0",
3636
"symfony/process": "~2.0,>=2.0.5|~3.0.0",
37-
"symfony/routing": "~2.2|~3.0.0",
37+
"symfony/routing": "~2.7|~3.0.0",
3838
"symfony/stopwatch": "~2.3|~3.0.0",
3939
4040
"symfony/translation": "~2.0,>=2.0.5|~3.0.0",
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Loader;
13+
14+
use Symfony\Component\Config\Loader\FileLoader;
15+
use Symfony\Component\Routing\RouteCollection;
16+
use Symfony\Component\Config\Resource\DirectoryResource;
17+
18+
class DirectoryLoader extends FileLoader
19+
{
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
public function load($file, $type = null)
24+
{
25+
$path = $this->locator->locate($file);
26+
27+
$collection = new RouteCollection();
28+
$collection->addResource(new DirectoryResource($path));
29+
30+
foreach (scandir($path) as $dir) {
31+
if ($dir[0] !== '.') {
32+
$this->setCurrentDir($path);
33+
$subPath = $path.'/'.$dir;
34+
$subType = null;
35+
36+
if (is_dir($subPath)) {
37+
$subPath .= '/';
38+
10000 $subType = 'directory';
39+
}
40+
41+
$subCollection = $this->import($subPath, $subType, false, $path);
42+
$collection->addCollection($subCollection);
43+
}
44+
}
45+
46+
return $collection;
47+
}
48+
49+
/**
50+
* {@inheritdoc}
51+
*/
52+
public function supports($resource, $type = null)
53+
{
54+
// only when type is forced to directory, not to conflict with AnnotationLoader
55+
56+
return 'directory' === $type;
57+
}
58+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
route1:
2+
path: /route/1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
route2:
2+
path: /route/2
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
route3:
2+
path: /route/3
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
_directory:
2+
resource: "../directory"
3+
type: directory
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Loader;
13+
14+
use Symfony\Component\Routing\Loader\DirectoryLoader;
15+
use Symfony\Component\Routing\Loader\YamlFileLoader;
16+
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
17+
use Symfony\Component\Config\Loader\LoaderResolver;
18+
use Symfony\Component\Config\FileLocator;
19+
use Symfony\Component\Routing\RouteCollection;
20+
21+
class DirectoryLoaderTest extends AbstractAnnotationLoaderTest
22+
{
23+
private $loader;
24+
private $reader;
25+
26+
protected function setUp()
27+
{
28+
parent::setUp();
29+
30+
$locator = new FileLocator();
31+
$this->reader = $this->getReader();
32+
$this->loader = new DirectoryLoader($locator);
33+
$resolver = new LoaderResolver(array(
34+
new YamlFileLoader($locator),
35+
new AnnotationFileLoader($locator, $this->getClassLoader($this->reader)),
36+
$this->loader,
37+
));
38+
$this->loader->setResolver($resolver);
39+
}
40+
41+
public function testLoadDirectory()
42+
{
43+
$collection = $this->loader->load(__DIR__.'/../Fixtures/directory', 'directory');
44+
$this->verifyCollection($collection);
45+
}
46+
47+
public function testImportDirectory()
48+
{
49+
$collection = $this->loader->load(__DIR__.'/../Fixtures/directory_import', 'directory');
50+
$this->verifyCollection($collection);
51+
}
52+
53+
private function verifyCollection(RouteCollection $collection)
54+
{
55+
$routes = $collection->all();
56+
57+
$this->assertCount(3, $routes, 'Three routes are loaded');
58+
$this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
59+
60+
for ($i = 1; $i <= 3; $i++) {
61+
$this->assertSame('/route/'.$i, $routes["route".$i]->getPath());
62+
}
63+
}
64+
65+
public function testSupports()
66+
{
67+
$fixturesDir = __DIR__.'/../Fixtures';
68+
69+
$this->assertFalse($this->loader->supports($fixturesDir), '->supports(*) returns false');
70+
71+
$this->assertTrue($this->loader->supports($fixturesDir, 'directory'), '->supports(*, "directory") returns true');
72+
$this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports(*, "foo") returns false');
73+
}
74+
}

0 commit comments

Comments
 (0)
0