Skip to content

Commit bbef5bd

Browse files
committed
[HttpKernel] Handle multi-attribute controller arguments
1 parent adbb341 commit bbef5bd

File tree

9 files changed

+59
-12
lines changed

9 files changed

+59
-12
lines changed

UPGRADE-5.3.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ HttpFoundation
4444
HttpKernel
4545
----------
4646

47+
* Deprecate `ArgumentInterface`
48+
* Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
4749
* Marked the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal
4850

4951
Messenger

UPGRADE-6.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ HttpFoundation
9292
HttpKernel
9393
----------
9494

95+
* Remove `ArgumentInterface`
96+
* Remove `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead
9597
* Made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+
9698
* Removed support for `service:action` syntax to reference controllers. Use `serviceOrFqcn::method` instead.
9799

src/Symfony/Component/HttpKernel/Attribute/ArgumentInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111

1212
namespace Symfony\Component\HttpKernel\Attribute;
1313

14+
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" interface is deprecated.', ArgumentInterface::class);
15+
1416
/**
1517
* Marker interface for controller argument attributes.
18+
*
19+
* @deprecated since Symfony 5.3
1620
*/
1721
interface ArgumentInterface
1822
{

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
5.3
55
---
66

7+
* Deprecate `ArgumentInterface`
8+
* Deprecate `ArgumentMetadata::getAttribute()`, use `getAttibutes()` instead
79
* marked the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal
810

911
5.2.0

src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadata.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,26 @@ class ArgumentMetadata
2626
private $hasDefaultValue;
2727
private $defaultValue;
2828
private $isNullable;
29-
private $attribute;
29+
private $attributes;
3030

31-
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, ?ArgumentInterface $attribute = null)
31+
/**
32+
* @param object[] $attributes A list of PHP Attribute instances
33+
*/
34+
public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, $attributes = [])
3235
{
3336
$this->name = $name;
3437
$this->type = $type;
3538
$this->isVariadic = $isVariadic;
3639
$this->hasDefaultValue = $hasDefaultValue;
3740
$this->defaultValue = $defaultValue;
3841
$this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue);
39-
$this->attribute = $attribute;
42+
43+
if (null === $attributes || $attributes instanceof ArgumentInterface) {
44+
trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" constructor expects an array of PHP attributes as last argument, %s given.', __CLASS__, get_debug_type($attributes));
45+
$attributes = $attributes ? [$attributes] : [];
46+
}
47+
48+
$this->attributes = $attributes;
4049
}
4150

4251
/**
@@ -114,6 +123,17 @@ public function getDefaultValue()
114123
*/
115124
public function getAttribute(): ?ArgumentInterface
116125
{
117-
return $this->attribute;
126+
trigger_deprecation('symfony/http-kernel', '5.3', 'Method "%s()" is deprecated, use "getAttributes()" instead.', __METHOD__);
127+
128+
if (!$this->attributes) {
129+
return null;
130+
}
131+
132+
return $this->attributes[0] instanceof ArgumentInterface ? $this->attributes[0] : null;
133+
}
134+
135+
public function getAttributes(): array
136+
{
137+
return $this->attributes;
118138
}
119139
}

src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\HttpKernel\ControllerMetadata;
1313

14-
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
1514
use Symfony\Component\HttpKernel\Exception\InvalidMetadataException;
1615

1716
/**
@@ -37,9 +36,9 @@ public function createArgumentMetadata($controller): array
3736
}
3837

3938
foreach ($reflection->getParameters() as $param) {
40-
$attribute = null;
39+
$attributes = [];
4140
if (\PHP_VERSION_ID >= 80000) {
42-
$reflectionAttributes = $param->getAttributes(ArgumentInterface::class, \ReflectionAttribute::IS_INSTANCEOF);
41+
$reflectionAttributes = $param->getAttributes();
4342

4443
if (\count($reflectionAttributes) > 1) {
4544
$representative = $controller;
@@ -53,12 +52,12 @@ public function createArgumentMetadata($controller): array
5352
throw new InvalidMetadataException(sprintf('Controller "%s" has more than one attribute for "$%s" argument.', $representative, $param->getName()));
5453
}
5554

56-
if (isset($reflectionAttributes[0])) {
57-
$attribute = $reflectionAttributes[0]->newInstance();
55+
foreach ($reflectionAttributes as $reflectionAttribute) {
56+
$attributes[] = $reflectionAttribute->newInstance();
5857
}
5958
}
6059

61-
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attribute);
60+
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes);
6261
}
6362

6463
return $arguments;

src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public function testAttributeSignature()
128128
$arguments = $this->factory->createArgumentMetadata([new AttributeController(), 'action']);
129129

130130
$this->assertEquals([
131-
new ArgumentMetadata('baz', 'string', false, false, null, false, new Foo('bar')),
131+
new ArgumentMetadata('baz', 'string', false, false, null, false, [new Foo('bar')]),
132132
], $arguments);
133133
}
134134

src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
namespace Symfony\Component\HttpKernel\Tests\ControllerMetadata;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
16+
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
1517
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
1618

1719
class ArgumentMetadataTest extends TestCase
1820
{
21+
use ExpectDeprecationTrait;
22+
1923
public function testWithBcLayerWithDefault()
2024
{
2125
$argument = new ArgumentMetadata('foo', 'string', false, true, 'default value');
@@ -41,4 +45,18 @@ public function testDefaultValueUnavailable()
4145
$this->assertFalse($argument->hasDefaultValue());
4246
$argument->getDefaultValue();
4347
}
48+
49+
/**
50+
* @group legacy
51+
*/
52+
public function testLegacyAttribute()
53+
{
54+
$attribute = $this->createMock(ArgumentInterface::class);
55+
56+
$this->expectDeprecation('Since symfony/http-kernel 5.3: The "Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata" constructor expects an array of PHP attributes as last argument, %s given.');
57+
$this->expectDeprecation('Since symfony/http-kernel 5.3: Method "Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata::getAttribute()" is deprecated, use "getAttributes()" instead.');
58+
59+
$argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true, $attribute);
60+
$this->assertSame($attribute, $argument->getAttribute());
61+
}
4462
}

src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/Foo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Symfony\Component\HttpKernel\Attribute\ArgumentInterface;
1515

1616
#[\Attribute(\Attribute::TARGET_PARAMETER)]
17-
class Foo implements ArgumentInterface
17+
class Foo
1818
{
1919
private $foo;
2020

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