8000 Fix delegating to PSR-4 loader from subdirectory · symfony/symfony@c1f0ccb · GitHub
[go: up one dir, main page]

Skip to content

Commit c1f0ccb

Browse files
derrabusfabpot
authored andcommitted
Fix delegating to PSR-4 loader from subdirectory
1 parent 455bd43 commit c1f0ccb

File tree

9 files changed

+106
-9
lines changed

9 files changed

+106
-9
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Config\Loader;
13+
14+
/**
15+
* A loader that can be scoped to a given filesystem directory.
16+
*
17+
* @author Alexander M. Turek <me@derrabus.de>
18+
*/
19+
interface DirectoryAwareLoaderInterface
20+
{
21+
public function forDirectory(string $currentDirectory): static;
22+
}

src/Symfony/Component/Config/Loader/FileLoader.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ public function getLocator(): FileLocatorInterface
6262
* @param string|null $sourceResource The original resource importing the new resource
6363
* @param string|string[]|null $exclude Glob patterns to exclude from the import
6464
*
65-
* @return mixed
66-
*
6765
* @throws LoaderLoadException
6866
* @throws FileLoaderImportCircularReferenceException
6967
* @throws FileLocatorFileNotFoundException
@@ -136,6 +134,10 @@ private function doImport(mixed $resource, string $type = null, bool $ignoreErro
136134
try {
137135
$loader = $this->resolve($resource, $type);
138136

137+
if ($loader instanceof DirectoryAwareLoaderInterface) {
138+
$loader = $loader->forDirectory($this->currentDir);
139+
}
140+
139141
if (!$loader instanceof self) {
140142
return $loader->load($resource, $type);
141143
}

src/Symfony/Component/Routing/Loader/Psr4DirectoryLoader.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212
namespace Symfony\Component\Routing\Loader;
1313

1414
use Symfony\Component\Config\FileLocatorInterface;
15+
use Symfony\Component\Config\Loader\DirectoryAwareLoaderInterface;
1516
use Symfony\Component\Config\Loader\Loader;
17+
use Symfony\Component\Config\Resource\DirectoryResource;
1618
use Symfony\Component\Routing\RouteCollection;
1719

1820
/**
1921
* A loader that discovers controller classes in a directory that follows PSR-4.
2022
*
2123
* @author Alexander M. Turek <me@derrabus.de>
2224
*/
23-
final class Psr4DirectoryLoader extends Loader
25+
final class Psr4DirectoryLoader extends Loader implements DirectoryAwareLoaderInterface
2426
{
27+
private ?string $currentDirectory = null;
28+
2529
public function __construct(
2630
private readonly FileLocatorInterface $locator,
2731
) {
@@ -34,7 +38,7 @@ public function __construct(
3438
*/
3539
public function load(mixed $resource, string $type = null): ?RouteCollection
3640
{
37-
$path = $this->locator->locate($resource['path']);
41+
$path = $this->locator->locate($resource['path'], $this->currentDirectory);
3842
if (!is_dir($path)) {
3943
return new RouteCollection();
4044
}
@@ -47,12 +51,33 @@ public function supports(mixed $resource, string $type = null): bool
4751
return ('attribute' === $type || 'annotation' === $type) && \is_array($resource) && isset($resource['path'], $resource['namespace']);
4852
}
4953

54+
public function forDirectory(string $currentDirectory): static
55+
{
56+
$loader = clone $this;
57+
$loader->currentDirectory = $currentDirectory;
58+
59+
return $loader;
60+
}
61+
5062
private function loadFromDirectory(string $directory, string $psr4Prefix): RouteCollection
5163
{
5264
$collection = new RouteCollection();
65+
$collection->addResource(new DirectoryResource($directory, '/\.php$/'));
66+
$files = iterator_to_array(new \RecursiveIteratorIterator(
67+
new \RecursiveCallbackFilterIterator(
68+
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
69+
function (\SplFileInfo $current) {
70+
return !str_starts_with($current->getBasename(), '.');
71+
}
72+
),
73+
\RecursiveIteratorIterator::LEAVES_ONLY
74+
));
75+
usort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
76+
return (string) $a > (string) $b ? 1 : -1;
77+
});
5378

5479
/** @var \SplFileInfo $file */
55-
foreach (new \FilesystemIterator($directory) as $file) {
80+
foreach ($files as $file) {
5681
if ($file->isDir()) {
5782
$collection->addCollection($this->loadFromDirectory($file->getPathname(), $psr4Prefix.'\\'.$file->getFilename()));
5883

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
https://symfony.com/schema/routing/routing-1.0.xsd">
6+
7+
<import resource="psr4-controllers-redirection/psr4-attributes.xml" />
8+
</routes>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
controllers:
2+
resource: psr4-controllers-redirection/psr4-attributes.yaml
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
https://symfony.com/schema/routing/routing-1.0.xsd">
6+
7+
<import prefix="/my-prefix" type="attribute">
8+
<resource path="../Psr4Controllers" namespace="Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers" />
9+
</import>
10+
</routes>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
my_controllers:
2+
resource:
3+
path: ../Psr4Controllers
4+
namespace: Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers
5+
type: attribute
6+
prefix: /my-prefix

src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,10 @@ public function testImportingAliases()
597597
$this->assertEquals($expectedRoutes('xml'), $routes);
598598
}
599599

600-
public function testImportAttributesWithPsr4Prefix()
600+
/**
601+
* @dataProvider providePsr4ConfigFiles
602+
*/
603+
public function testImportAttributesWithPsr4Prefix(string $configFile)
601604
{
602605
$locator = new FileLocator(\dirname(__DIR__).'/Fixtures');
603606
new LoaderResolver([
@@ -611,11 +614,19 @@ protected function configureRoute(Route $route, \ReflectionClass $class, \Reflec
611614
},
612615
]);
613616

614-
$route = $loader->load('psr4-attributes.xml')->get('my_route');
617+
$route = $loader->load($configFile)->get('my_route');
615618
$this->assertSame('/my-prefix/my/route', $route->getPath());
616619
$this->assertSame(MyController::class.'::__invoke', $route->getDefault('_controller'));
617620
}
618621

622+
public function providePsr4ConfigFiles(): array
623+
{
624+
return [
625+
['psr4-attributes.xml'],
626+
['psr4-controllers-redirection.xml'],
627+
];
628+
}
629+
619630
public function testImportAttributesFromClass()
620631
{
621632
new LoaderResolver([

src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,10 @@ public function testImportingAliases()
463463
$this->assertEquals($expectedRoutes('yaml'), $routes);
464464
}
465465

466-
public function testImportAttributesWithPsr4Prefix()
466+
/**
467+
* @dataProvider providePsr4ConfigFiles
468+
*/
469+
public function testImportAttributesWithPsr4Prefix(string $configFile)
467470
{
468471
$locator = new FileLocator(\dirname(__DIR__).'/Fixtures');
469472
new LoaderResolver([
@@ -477,11 +480,19 @@ protected function configureRoute(Route $route, \ReflectionClass $class, \Reflec
477480
},
478481
]);
479482

480-
$route = $loader->load('psr4-attributes.yaml')->get('my_route');
483+
$route = $loader->load($configFile)->get('my_route');
481484
$this->assertSame('/my-prefix/my/route', $route->getPath());
482485
$this->assertSame(MyController::class.'::__invoke', $route->getDefault('_controller'));
483486
}
484487

488+
public function providePsr4ConfigFiles(): array
489+
{
490+
return [
491+
['psr4-attributes.yaml'],
492+
['psr4-controllers-redirection.yaml'],
493+
];
494+
}
495+
485496
public function testImportAttributesFromClass()
486497
{
487498
new LoaderResolver([

0 commit comments

Comments
 (0)
0