Skip to content

Commit ca69a18

Browse files
[HttpKernel] Fix extracting controller name from closures
1 parent b3347b3 commit ca69a18

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

ControllerMetadata/ArgumentMetadataFactory.php

+12-8
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,19 @@ public function createArgumentMetadata($controller): array
2727

2828
if (\is_array($controller)) {
2929
$reflection = new \ReflectionMethod($controller[0], $controller[1]);
30+
$class = $reflection->class;
3031
} elseif (\is_object($controller) && !$controller instanceof \Closure) {
31-
$reflection = (new \ReflectionObject($controller))->getMethod('__invoke');
32+
$reflection = new \ReflectionMethod($controller, '__invoke');
33+
$class = $reflection->class;
3234
} else {
3335
$reflection = new \ReflectionFunction($controller);
36+
if ($class = str_contains($reflection->name, '{closure}') ? null : $reflection->getClosureScopeClass()) {
37+
$class = $class->name;
38+
}
3439
}
3540

3641
foreach ($reflection->getParameters() as $param) {
37-
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
42+
$arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull());
3843
}
3944

4045
return $arguments;
@@ -43,20 +48,19 @@ public function createArgumentMetadata($controller): array
4348
/**
4449
* Returns an associated type to the given parameter if available.
4550
*/
46-
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function): ?string
51+
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function, ?string $class): ?string
4752
{
4853
if (!$type = $parameter->getType()) {
4954
return null;
5055
}
5156
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
5257

53-
if ($function instanceof \ReflectionMethod) {
54-
$lcName = strtolower($name);
55-
switch ($lcName) {
58+
if (null !== $class) {
59+
switch (strtolower($name)) {
5660
case 'self':
57-
return $function->getDeclaringClass()->name;
61+
return $class;
5862
case 'parent':
59-
return ($parent = $function->getDeclaringClass()->getParentClass()) ? $parent->name : null;
63+
return get_parent_class($class) ?: null;
6064
}
6165
}
6266

Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php

+11
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ public function testBasicTypesSignature()
105105
], $arguments);
106106
}
107107

108+
public function testNamedClosure()
109+
{
110+
$arguments = $this->factory->createArgumentMetadata(\Closure::fromCallable([$this, 'signature1']));
111+
112+
$this->assertEquals([
113+
new ArgumentMetadata('foo', self::class, false, false, null),
114+
new ArgumentMetadata('bar', 'array', false, false, null),
115+
new ArgumentMetadata('baz', 'callable', false, false, null),
116+
], $arguments);
117+
}
118+
108119
public function testNullableTypesSignature()
109120
{
110121
$arguments = $this->factory->createArgumentMetadata([new NullableController(), 'action']);

0 commit comments

Comments
 (0)