Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 11ef7d9

Browse filesBrowse files
committed
[HttpKernel] Add the UidValueResolver argument value resolver
1 parent a14eb3f commit 11ef7d9
Copy full SHA for 11ef7d9

File tree

12 files changed

+351
-0
lines changed
Filter options

12 files changed

+351
-0
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
8181
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
8282
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\BackedEnumValueResolver;
83+
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\UidValueResolver;
8384
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
8485
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
8586
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@@ -416,6 +417,8 @@ public function load(array $configs, ContainerBuilder $container)
416417
}
417418

418419
$this->registerUidConfiguration($config['uid'], $container, $loader);
420+
} else {
421+
$container->removeDefinition('argument_resolver.uid');
419422
}
420423

421424
// register cache before session so both can share the connection services
@@ -2577,6 +2580,10 @@ private function registerUidConfiguration(array $config, ContainerBuilder $conta
25772580
$container->getDefinition('name_based_uuid.factory')
25782581
->setArguments([$config['name_based_uuid_namespace']]);
25792582
}
2583+
2584+
if (!class_exists(UidValueResolver::class)) {
2585+
$container->removeDefinition('argument_resolver.uid');
2586+
}
25802587
}
25812588

25822589
private function resolveTrustedHeaders(array $headers): int

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
2020
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver;
2121
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver;
22+
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\UidValueResolver;
2223
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
2324
use Symfony\Component\HttpKernel\Controller\ErrorController;
2425
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
@@ -50,6 +51,11 @@
5051
'priority' => 105, // prior to the RequestAttributeValueResolver
5152
])
5253

54+
->set('argument_resolver.uid', UidValueResolver::class)
55+
->tag('controller.argument_value_resolver', [
56+
'priority' => 100, // same priority than RequestAttributeValueResolver, but registered before
57+
])
58+
5359
->set('argument_resolver.request_attribute', RequestAttributeValueResolver::class)
5460
->tag('controller.argument_value_resolver', ['priority' => 100])
5561

+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller;
13+
14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\Routing\Annotation\Route;
16+
use Symfony\Component\Routing\Requirement;
17+
use Symfony\Component\Uid\Ulid;
18+
use Symfony\Component\Uid\UuidV1;
19+
20+
class UidController
21+
{
22+
#[Route(path: '/1/uuid-v1/{userId}')]
23+
public function anyFormat(UuidV1 $userId): Response
24+
{
25+
return new Response($userId);
26+
}
27+
28+
#[Route(path: '/2/ulid/{id}', requirements: ['id' => '[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}'])]
29+
public function specificFormatInAttribute(Ulid $id): Response
30+
{
31+
return new Response($id);
32+
}
33+
34+
#[Route(path: '/3/uuid-v1/{id<[0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz]{26}>}')]
35+
public function specificFormatInPath(UuidV1 $id): Response
36+
{
37+
return new Response($id);
38+
}
39+
40+
#[Route(path: '/4/uuid-v1/{postId}/custom-uid/{commentId}')]
41+
public function manyUids(UuidV1 $postId, TestCommentIdentifier $commentId): Response
42+
{
43+
return new Response($postId."\n".$commentId);
44+
}
45+
}
46+
47+
class TestCommentIdentifier extends Ulid
48+
{
49+
}

‎src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ array_controller:
6060
send_email:
6161
path: /send_email
6262
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\EmailController::indexAction }
63+
64+
uid:
65+
resource: "../../Controller/UidController.php"
66+
type: "annotation"
+90Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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\Bundle\FrameworkBundle\Tests\Functional;
13+
14+
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\UidController;
15+
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\UidValueResolver;
16+
use Symfony\Component\Uid\Ulid;
17+
use Symfony\Component\Uid\UuidV1;
18+
use Symfony\Component\Uid\UuidV4;
19+
use Symfony\Component\Uid\UuidV6;
20+
21+
/**
22+
* @see UidController
23+
*/
24+
class UidTest extends AbstractWebTestCase
25+
{
26+
protected function setUp(): void
27+
{
28+
parent::setUp();
29+
30+
self::deleteTmpDir();
31+
}
32+
33+
public function testArgumentValueResolverDisabled()
34+
{
35+
$this->expectException(\TypeError::class);
36+
$this->expectExceptionMessage('Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\UidController::anyFormat(): Argument #1 ($userId) must be of type Symfony\Component\Uid\UuidV1, string given');
37+
38+
$client = $this->createClient(['test_case' => 'Uid', 'root_config' => 'config_disabled.yml']);
39+
40+
$client->request('GET', '/1/uuid-v1/'.new UuidV1());
41+
}
42+
43+
public function testArgumentValueResolverEnabled()
44+
{
45+
if (!class_exists(UidValueResolver::class)) {
46+
$this->markTestSkipped('Needs symfony/http-kernel >= 6.1');
47+
}
48+
49+
$client = $this->createClient(['test_case' => 'Uid', 'root_config' => 'config_enabled.yml']);
50+
51+
// Any format
52+
$client->request('GET', '/1/uuid-v1/'.$uuidV1 = new UuidV1());
53+
$this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
54+
$client->request('GET', '/1/uuid-v1/'.$uuidV1->toBase58());
55+
$this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
56+
$client->request('GET', '/1/uuid-v1/'.$uuidV1->toRfc4122());
57+
$this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
58+
// Bad version
59+
$client->request('GET', '/1/uuid-v1/'.$uuidV4 = new UuidV4());
60+
$this->assertSame(404, $client->getResponse()->getStatusCode());
61+
62+
// Only base58 format
63+
$client->request('GET', '/2/ulid/'.($ulid = new Ulid())->toBase58());
64+
$this->assertSame((string) $ulid, $client->getResponse()->getContent());
65+
$client->request('GET', '/2/ulid/'.$ulid);
66+
$this->assertSame(404, $client->getResponse()->getStatusCode());
67+
$client->request('GET', '/2/ulid/'.$ulid->toRfc4122());
68+
$this->assertSame(404, $client->getResponse()->getStatusCode());
69+
70+
// Only base32 format
71+
$client->request('GET', '/3/uuid-v1/'.$uuidV1->toBase32());
72+
$this->assertSame((string) $uuidV1, $client->getResponse()->getContent());
73+
$client->request('GET', '/3/uuid-v1/'.$uuidV1);
74+
$this->assertSame(404, $client->getResponse()->getStatusCode());
75+
$client->request('GET', '/3/uuid-v1/'.$uuidV1->toBase58());
76+
$this->assertSame(404, $client->getResponse()->getStatusCode());
77+
// Bad version
78+
$client->request('GET', '/3/uuid-v1/'.(new UuidV6())->toBase32());
79+
$this->assertSame(404, $client->getResponse()->getStatusCode());
80+
81+
// Any format for both
82+
$client->request('GET', '/4/uuid-v1/'.$uuidV1.'/custom-uid/'.$ulid->toRfc4122());
83+
$this->assertSame($uuidV1."\n".$ulid, $client->getResponse()->getContent());
84+
$client->request('GET', '/4/uuid-v1/'.$uuidV1->toBase58().'/custom-uid/'.$ulid->toBase58());
85+
$this->assertSame($uuidV1."\n".$ulid, $client->getResponse()->getContent());
86+
// Bad version
87+
$client->request('GET', '/4/uuid-v1/'.$uuidV4.'/custom-uid/'.$ulid);
88+
$this->assertSame(404, $client->getResponse()->getStatusCode());
89+
}
90+
}
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
13+
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
14+
15+
return [
16+
new FrameworkBundle(),
17+
new TestBundle(),
18+
];
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports:
2+
- { resource: "../config/default.yml" }
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
imports:
2+
- { resource: "../config/default.yml" }
3+
4+
framework:
5+
uid: ~
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
uid:
2+
resource: "@TestBundle/Resources/config/routing.yml"

‎src/Symfony/Component/HttpKernel/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Add `BackedEnumValueResolver` to resolve backed enum cases from request attributes in controller arguments
88
* Deprecate StreamedResponseListener, it's not needed anymore
99
* Add `Profiler::isEnabled()` so collaborating collector services may elect to omit themselves.
10+
* Add the `UidValueResolver` argument value resolver
1011

1112
6.0
1213
---
+47Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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\HttpKernel\Controller\ArgumentResolver;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
16+
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
17+
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
18+
use Symfony\Component\Uid\AbstractUid;
19+
20+
final class UidValueResolver implements ArgumentValueResolverInterface
21+
{
22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public function supports(Request $request, ArgumentMetadata $argument): bool
26+
{
27+
return !$argument->isVariadic()
28+
&& \is_string($request->attributes->get($argument->getName()))
29+
&& null !== $argument->getType()
30+
&& is_subclass_of($argument->getType(), AbstractUid::class, true);
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
public function resolve(Request $request, ArgumentMetadata $argument): iterable
37+
{
38+
/** @var class-string<AbstractUid> $uidClass */
39+
$uidClass = $argument->getType();
40+
41+
try {
42+
return [$uidClass::fromString($request->attributes->get($argument->getName()))];
43+
} catch (\InvalidArgumentException $e) {
44+
throw new NotFoundHttpException(sprintf('The uid for the "%s" parameter is invalid.', $argument->getName()), $e);
45+
}
46+
}
47+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.