Skip to content

Commit 19f3e39

Browse files
committed
[HttpKernel] Add the UidValueResolver argument value resolver
1 parent 299ac1c commit 19f3e39

File tree

12 files changed

+351
-0
lines changed

12 files changed

+351
-0
lines changed

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

Lines 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

Lines 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

Lines 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' => Requirement::BASE58])]
29+
public function specificFormatInAttribute(Ulid $id): Response
30+
{
31+
return new Response($id);
32+
}
33+
34+
#[Route(path: '/3/uuid-v1/{id<'.Requirement::BASE32.'>}')]
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

Lines 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"
Lines 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+
}
Lines 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+
];
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports:
2+
- { resource: "../config/default.yml" }
Lines 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: ~
Lines 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

Lines 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
---

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy