Skip to content

Commit 45dad94

Browse files
authored
fix(metadata): match parameter subclasses in Parameters lookups (#8710)
1 parent 23c4876 commit 45dad94

2 files changed

Lines changed: 54 additions & 16 deletions

File tree

‎src/Metadata/Parameters.php‎

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,13 @@ private static function propertyDiscriminator(Parameter $parameter): string
105105
*/
106106
public function remove(string $key, string $parameterClass = QueryParameter::class): self
107107
{
108-
foreach ($this->parameters as $i => [$parameterName, $parameter]) {
109-
if ($parameterName === $key && $parameterClass === $parameter::class) {
110-
unset($this->parameters[$i]);
111-
112-
return $this;
113-
}
108+
if (null === $i = $this->indexOf($key, $parameterClass)) {
109+
throw new RuntimeException(\sprintf('Could not remove parameter "%s".', $key));
114110
}
115111

116-
throw new RuntimeException(\sprintf('Could not remove parameter "%s".', $key));
112+
unset($this->parameters[$i]);
113+
114+
return $this;
117115
}
118116

119117
/**
@@ -125,13 +123,11 @@ public function remove(string $key, string $parameterClass = QueryParameter::cla
125123
*/
126124
public function get(string $key, string $parameterClass = QueryParameter::class): ?Parameter
127125
{
128-
foreach ($this->parameters as [$parameterName, $parameter]) {
129-
if ($parameterName === $key && $parameterClass === $parameter::class) {
130-
return $parameter;
131-
}
126+
if (null === $i = $this->indexOf($key, $parameterClass)) {
127+
return null;
132128
}
133129

134-
return null;
130+
return $this->parameters[$i][1];
135131
}
136132

137133
/**
@@ -141,13 +137,27 @@ public function get(string $key, string $parameterClass = QueryParameter::class)
141137
*/
142138
public function has(string $key, string $parameterClass = QueryParameter::class): bool
143139
{
144-
foreach ($this->parameters as [$parameterName, $parameter]) {
145-
if ($parameterName === $key && $parameterClass === $parameter::class) {
146-
return true;
140+
return null !== $this->indexOf($key, $parameterClass);
141+
}
142+
143+
private function indexOf(string $key, string $parameterClass): ?int
144+
{
145+
$subclassMatch = null;
146+
foreach ($this->parameters as $i => [$parameterName, $parameter]) {
147+
if ($parameterName !== $key) {
148+
continue;
149+
}
150+
151+
if ($parameterClass === $parameter::class) {
152+
return $i;
153+
}
154+
155+
if (null === $subclassMatch && $parameter instanceof $parameterClass) {
156+
$subclassMatch = $i;
147157
}
148158
}
149159

150-
return false;
160+
return $subclassMatch;
151161
}
152162

153163
public function count(): int

‎src/Metadata/Tests/ParametersTest.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Metadata\HeaderParameter;
1717
use ApiPlatform\Metadata\Parameters;
1818
use ApiPlatform\Metadata\QueryParameter;
19+
use ApiPlatform\Metadata\ScalarHeaderParameter;
1920
use PHPUnit\Framework\TestCase;
2021

2122
class ParametersTest extends TestCase
@@ -77,4 +78,31 @@ public function testPropertyPlaceholderKeysAreNotDeduplicatedViaAdd(): void
7778

7879
$this->assertCount(2, $parameters);
7980
}
81+
82+
public function testLookupMatchesSubclass(): void
83+
{
84+
$scalar = new ScalarHeaderParameter(key: 'Foo');
85+
$parameters = new Parameters([$scalar]);
86+
87+
$this->assertSame($scalar, $parameters->get('Foo', HeaderParameter::class));
88+
$this->assertTrue($parameters->has('Foo', HeaderParameter::class));
89+
$this->assertFalse($parameters->has('Foo'));
90+
91+
$parameters->remove('Foo', HeaderParameter::class);
92+
$this->assertCount(0, $parameters);
93+
}
94+
95+
public function testLookupPrefersExactClassOverSubclass(): void
96+
{
97+
$scalar = new ScalarHeaderParameter(key: 'Foo');
98+
$header = new HeaderParameter(key: 'Foo');
99+
$parameters = new Parameters([$scalar, $header]);
100+
101+
$this->assertSame($header, $parameters->get('Foo', HeaderParameter::class));
102+
$this->assertSame($scalar, $parameters->get('Foo', ScalarHeaderParameter::class));
103+
104+
$parameters->remove('Foo', HeaderParameter::class);
105+
$this->assertCount(1, $parameters);
106+
$this->assertSame($scalar, $parameters->get('Foo', HeaderParameter::class));
107+
}
80108
}

0 commit comments

Comments
 (0)