8000 feature #47943 [Config][Routing] Nicer config syntax for PSR-4 route … · symfony/symfony@22481f2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 22481f2

Browse files
committed
feature #47943 [Config][Routing] Nicer config syntax for PSR-4 route loading (derrabus)
This PR was merged into the 6.2 branch. Discussion ---------- [Config][Routing] Nicer config syntax for PSR-4 route loading | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Follow-up to #47916 | License | MIT | Doc PR | symfony/symfony-docs#17373 (WIP) This PR implements an alternative syntax for the PSR-4 route loader introduced in #47916. ```YAML controllers: resource: path: ./Controllers namespace: App\Controllers type: attribute ``` ```XML <routes> <import type="attribute"> <resource path="./Controllers" namespace="App\Psr4Controllers" /> </import> </routes> ``` Commits ------- d7df3be Nicer config syntax for PSR-4 route loading
2 parents cf073c4 + d7df3be commit 22481f2

File tree

11 files changed

+78
-34
lines changed

11 files changed

+78
-34
lines changed
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
test_bundle:
22
prefix: /annotated
3-
resource: "@TestBundle/Controller"
4-
type: attribute@Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller
3+
resource:
4+
path: "@TestBundle/Controller"
5+
namespace: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller
6+
type: attribute

src/Symfony/Component/Config/Exception/LoaderLoadException.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,22 @@
1919
class LoaderLoadException extends \Exception
2020
{
2121
/**
22-
* @param string $resource The resource that could not be imported
22+
* @param mixed $resource The resource that could not be imported
2323
* @param string|null $sourceResource The original resource importing the new resource
2424
* @param int $code The error code
2525
* @param \Throwable|null $previous A previous exception
2626
* @param string|null $type The type of resource
2727
*/
28-
public function __construct(string $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null)
28+
public function __construct(mixed $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null)
2929
{
30+
if (!\is_string($resource)) {
31+
try {
32+
$resource = json_encode($resource, \JSON_THROW_ON_ERROR);
33+
} catch (\JsonException) {
34+
$resource = sprintf('resource of type "%s"', get_debug_type($resource));
35+
}
36+
}
37+
3038
$message = '';
3139
if ($previous) {
3240
// Include the previous exception, to help the user see what might be the underlying cause

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@ private function doImport(mixed $resource, string $type = null, bool $ignoreErro
136136
try {
137137
$loader = $this->resolve($resource, $type);
138138

139-
if ($loader instanceof self && null !== $this->currentDir) {
139+
if (!$loader instanceof self) {
140+
return $loader->load($resource, $type);
141+
}
142+
143+
if (null !== $this->currentDir) {
140144
$resource = $loader->getLocator()->locate($resource, $this->currentDir, false);
141145
}
142146

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,15 @@ function (\SplFileInfo $current) {
6666

6767
public function supports(mixed $resource, string $type = null): bool
6868
{
69+
if (!\is_string($resource)) {
70+
return false;
71+
}
72+
6973
if (\in_array($type, ['annotation', 'attribute'], true)) {
7074
return true;
7175
}
7276

73-
if ($type || !\is_string($resource)) {
77+
if ($type) {
7478
return false;
7579
}
7680

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,39 @@
1212
namespace Symfony\Component\Routing\Loader;
1313

1414
use Symfony\Component\Config\FileLocatorInterface;
15-
use Symfony\Component\Config\Loader\FileLoader;
15+
use Symfony\Component\Config\Loader\Loader;
1616
use Symfony\Component\Routing\RouteCollection;
1717

1818
/**
1919
* A loader that discovers controller classes in a directory that follows PSR-4.
2020
*
2121
* @author Alexander M. Turek <me@derrabus.de>
2222
*/
23-
final class Psr4DirectoryLoader extends FileLoader
23+
final class Psr4DirectoryLoader extends Loader
2424
{
25-
public function __construct(FileLocatorInterface $locator)
26-
{
25+
public function __construct(
26+
private readonly FileLocatorInterface $locator,
27+
) {
2728
// PSR-4 directory loader has no env-aware logic, so we drop the $env constructor parameter.
28-
parent::__construct($locator);
29+
parent::__construct();
2930
}
3031

32+
/**
33+
* @param array{path: string, namespace: string} $resource
34+
*/
3135
public function load(mixed $resource, string $type = null): ?RouteCollection
3236
{
33-
$path = $this->locator->locate($resource);
37+
$path = $this->locator->locate($resource['path']);
3438
if (!is_dir($path)) {
3539
return new RouteCollection();
3640
}
3741

38-
return $this->loadFromDirectory($path, trim(substr($type, 10), ' \\'));
42+
return $this->loadFromDirectory($path, trim($resource['namespace'], '\\'));
3943
}
4044

4145
public function supports(mixed $resource, string $type = null): bool
4246
{
43-
return \is_string($resource) && null !== $type && str_starts_with($type, 'attribute@');
47+
return ('attribute' === $type || 'annotation' === $type) && \is_array($resource) && isset($resource['path'], $resource['namespace']);
4448
}
4549

4650
private function loadFromDirectory(string $directory, string $psr4Prefix): RouteCollection

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,17 @@ protected function parseRoute(RouteCollection $collection, \DOMElement $node, st
151151
*/
152152
protected function parseImport(RouteCollection $collection, \DOMElement $node, string $path, string $file)
153153
{
154-
if ('' === $resource = $node->getAttribute('resource')) {
155-
throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute.', $path));
154+
/** @var \DOMElement $resourceElement */
155+
if (!($resource = $node->getAttribute('resource') ?: null) && $resourceElement = $node->getElementsByTagName('resource')[0] ?? null) {
156+
$resource = [];
157+
/** @var \DOMAttr $attribute */
158+
foreach ($resourceElement->attributes as $attribute) {
159+
$resource[$attribute->name] = $attribute->value;
160+
}
161+
}
162+
163+
if (!$resource) {
164+
throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute or element.', $path));
156165
}
157166

158167
$type = $node->getAttribute('type');
@@ -276,6 +285,8 @@ private function parseConfigs(\DOMElement $node, string $path): array
276285
case 'condition':
277286
$condition = trim($n->textContent);
278287
break;
288+
case 'resource':
289+
break;
279290
default:
280291
throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement", "option" or "condition".', $n->localName, $path));
281292
}

src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@
7676
<xsd:element name="prefix" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
7777
<xsd:element name="exclude" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
7878
<xsd:element name="host" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
79+
<xsd:element name="resource" type="resource" minOccurs="0" maxOccurs="1" />
7980
</xsd:sequence>
80-
<xsd:attribute name="resource" type="xsd:string" use="required" />
81+
<xsd:attribute name="resource" type="xsd:string" />
8182
<xsd:attribute name="type" type="xsd:string" />
8283
<xsd:attribute name="exclude" type="xsd:string" />
8384
<xsd:attribute name="prefix" type="xsd:string" />
@@ -93,6 +94,12 @@
9394
<xsd:attribute name="stateless" type="xsd:boolean" />
9495
</xsd:complexType>
9596

97+
<xsd:complexType name="resource">
98+
<xsd:attribute name="path" type="xsd:string" />
99+
<xsd:attribute name="namespace" type="xsd:string" />
100+
<xsd:anyAttribute />
101+
</xsd:complexType>
102+
96103
<xsd:complexType name="default" mixed="true">
97104
<xsd:choice minOccurs="0" maxOccurs="1">
98105
<xsd:element name="bool" type="xsd:boolean" />

src/Symfony/Component/Routing/Tests/Fixtures/psr4-attributes.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
xsi:schemaLocation="http://symfony.com/schema/routing
55
https://symfony.com/schema/routing/routing-1.0.xsd">
66

7-
<import resource="./Psr4Controllers" prefix="/my-prefix"
8-
type="attribute@Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers" />
7+
<import prefix="/my-prefix" type="attribute">
8+
<resource path="./Psr4Controllers" namespace="Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers" />
9+
</import>
910
</routes>
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
my_controllers:
2-
resource: ./Psr4Controllers
3-
type: attribute@Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers
2+
resource:
3+
path: ./Psr4Controllers
4+
namespace: Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers
5+
type: attribute
46
prefix: /my-prefix

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,34 +57,35 @@ public function testTraitController()
5757
}
5858

5959
/**
60-
* @dataProvider provideResourceTypesThatNeedTrimming
60+
* @dataProvider provideNamespacesThatNeedTrimming
6161
*/
62-
public function testPsr4NamespaceTrim(string $resourceType)
62+
public function testPsr4NamespaceTrim(string $namespace)
6363
{
6464
$route = $this->getLoader()
65-
->load('Psr4Controllers', $resourceType)
65+
->load(
66+
['path' => 'Psr4Controllers', 'namespace' => $namespace],
67+
'attribute',
68+
)
6669
->get('my_route');
67< 10000 /td>70

6871
$this->assertSame('/my/route', $route->getPath());
6972
$this->assertSame(MyController::class.'::__invoke', $route->getDefault('_controller'));
7073
}
7174

72-
public function provideResourceTypesThatNeedTrimming(): array
75+
public function provideNamespacesThatNeedTrimming(): array
7376
{
7477
return [
75-
['attribute@ Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'],
76-
['attribute@\\Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'],
77-
['attribute@Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers\\'],
78-
['attribute@\\Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers\\'],
79-
['attribute@ \\Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'],
78+
['\\Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'],
79+
['Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers\\'],
80+
['\\Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers\\'],
8081
];
8182
}
8283

8384
private function loadPsr4Controllers(): RouteCollection
8485
{
8586
return $this->getLoader()->load(
86-
'Psr4Controllers',
87-
'attribute@Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'
87+
['path' => 'Psr4Controllers', 'namespace' => 'Symfony\Component\Routing\Tests\Fixtures\Psr4Controllers'],
88+
'attribute'
8889
);
8990
}
9091

src/Symfony/Component/Routing/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"php": ">=8.1"
2020
},
2121
"require-dev": {
22-
"symfony/config": "^5.4|^6.0",
22+
"symfony/config": "^6.2",
2323
"symfony/http-foundation": "^5.4|^6.0",
2424
"symfony/yaml": "^5.4|^6.0",
2525
"symfony/expression-language": "^5.4|^6.0",
@@ -29,7 +29,7 @@
2929
},
< 5F2E /code>
3030
"conflict": {
3131
"doctrine/annotations": "<1.12",
32-
"symfony/config": "<5.4",
32+
"symfony/config": "<6.2",
3333
"symfony/dependency-injection": "<5.4",
3434
"symfony/yaml": "<5.4"
3535
},

0 commit comments

Comments
 (0)
0