Skip to content

Commit

Permalink
[HttpKernel] Fix extracting controller name from closures
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Feb 17, 2022
1 parent b3347b3 commit ca69a18
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 8 deletions.
20 changes: 12 additions & 8 deletions ControllerMetadata/ArgumentMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,19 @@ public function createArgumentMetadata($controller): array

if (\is_array($controller)) {
$reflection = new \ReflectionMethod($controller[0], $controller[1]);
$class = $reflection->class;
} elseif (\is_object($controller) && !$controller instanceof \Closure) {
$reflection = (new \ReflectionObject($controller))->getMethod('__invoke');
$reflection = new \ReflectionMethod($controller, '__invoke');
$class = $reflection->class;
} else {
$reflection = new \ReflectionFunction($controller);
if ($class = str_contains($reflection->name, '{closure}') ? null : $reflection->getClosureScopeClass()) {
$class = $class->name;
}
}

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

return $arguments;
Expand All @@ -43,20 +48,19 @@ public function createArgumentMetadata($controller): array
/**
* Returns an associated type to the given parameter if available.
*/
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function): ?string
private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function, ?string $class): ?string
{
if (!$type = $parameter->getType()) {
return null;
}
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;

if ($function instanceof \ReflectionMethod) {
$lcName = strtolower($name);
switch ($lcName) {
if (null !== $class) {
switch (strtolower($name)) {
case 'self':
return $function->getDeclaringClass()->name;
return $class;
case 'parent':
return ($parent = $function->getDeclaringClass()->getParentClass()) ? $parent->name : null;
return get_parent_class($class) ?: null;
}
}

Expand Down
11 changes: 11 additions & 0 deletions Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ public function testBasicTypesSignature()
], $arguments);
}

public function testNamedClosure()
{
$arguments = $this->factory->createArgumentMetadata(\Closure::fromCallable([$this, 'signature1']));

$this->assertEquals([
new ArgumentMetadata('foo', self::class, false, false, null),
new ArgumentMetadata('bar', 'array', false, false, null),
new ArgumentMetadata('baz', 'callable', false, false, null),
], $arguments);
}

public function testNullableTypesSignature()
{
$arguments = $this->factory->createArgumentMetadata([new NullableController(), 'action']);
Expand Down

0 comments on commit ca69a18

Please sign in to comment.