fix(Console): add void as valid return type for command methods
All checks were successful
Test Runner / test-php (push) Successful in 31s
Deploy Application / deploy (push) Successful in 1m42s
Test Runner / test-basic (push) Successful in 7s

The MethodSignatureAnalyzer was rejecting command methods with void return
type, causing the schedule:run command to fail validation.
This commit is contained in:
2025-11-26 06:16:09 +01:00
parent 386baff65f
commit c93d3f07a2
73 changed files with 1674 additions and 163 deletions

View File

@@ -61,7 +61,7 @@ final readonly class StackItem
private static function sanitizeArgs(array $args): array
{
return array_map(
fn($arg) => self::sanitizeValue($arg),
fn ($arg) => self::sanitizeValue($arg),
$args
);
}
@@ -77,6 +77,7 @@ final readonly class StackItem
$reflection = new \ReflectionFunction($value);
$file = $reflection->getFileName();
$line = $reflection->getStartLine();
return sprintf('Closure(%s:%d)', basename($file), $line);
} catch (\Throwable) {
return 'Closure';
@@ -102,6 +103,7 @@ final readonly class StackItem
if ($parentClass !== false) {
return sprintf('Anonymous(%s)', $parentClass);
}
return 'Anonymous';
}
@@ -112,7 +114,7 @@ final readonly class StackItem
// Arrays rekursiv bereinigen
if (is_array($value)) {
return array_map(
fn($item) => self::sanitizeValue($item),
fn ($item) => self::sanitizeValue($item),
$value
);
}
@@ -145,15 +147,17 @@ final readonly class StackItem
// Entferne Namespace: Spalte am Backslash und nimm den letzten Teil
$parts = explode('\\', $interfaceName);
$shortName = end($parts);
return $shortName . ' (anonymous)';
}
return 'Anonymous';
}
// Spalte am Backslash und nimm den letzten Teil (Klassenname ohne Namespace)
$parts = explode('\\', $normalizedClass);
$shortName = end($parts);
// Sicherstellen, dass wir wirklich nur den letzten Teil zurückgeben
// (falls explode() nicht funktioniert hat, z.B. bei Forward-Slashes)
if ($shortName === $normalizedClass && str_contains($normalizedClass, '/')) {
@@ -161,7 +165,7 @@ final readonly class StackItem
$parts = explode('/', $normalizedClass);
$shortName = end($parts);
}
return $shortName;
}
@@ -226,6 +230,7 @@ final readonly class StackItem
foreach ($this->args as $index => $arg) {
if ($index >= $maxArgs) {
$formatted[] = '…';
break;
}
@@ -235,6 +240,7 @@ final readonly class StackItem
if ($length > $maxTotalLength) {
$formatted[] = '…';
break;
}
}
@@ -271,6 +277,7 @@ final readonly class StackItem
if (class_exists($normalizedValue) || interface_exists($normalizedValue) || enum_exists($normalizedValue)) {
$parts = explode('\\', $normalizedValue);
$shortName = end($parts);
return sprintf("'%s'", $shortName);
}
@@ -282,6 +289,7 @@ final readonly class StackItem
// Nur wenn es mehrere Teile gibt (Namespace vorhanden)
if (count($parts) > 1) {
$shortName = end($parts);
return sprintf("'%s'", $shortName);
}
}
@@ -290,6 +298,7 @@ final readonly class StackItem
if (preg_match('/^Closure\(([^:]+):(\d+)\)$/', $value, $matches)) {
$file = basename($matches[1]);
$line = $matches[2];
return sprintf("Closure(%s:%s)", $file, $line);
}
@@ -319,8 +328,10 @@ final readonly class StackItem
$interfaceName = $matches[1];
$interfaceParts = explode('\\', $interfaceName);
$shortInterface = end($interfaceParts);
return $shortInterface . ' (anonymous)';
}
return 'Anonymous';
}
@@ -341,25 +352,26 @@ final readonly class StackItem
$closureInfo = $matches[1];
// Normalisiere Forward-Slashes zu Backslashes
$closureInfo = str_replace('/', '\\', $closureInfo);
// Parse: App\Framework\Router\RouteDispatcher::executeController():77
if (preg_match('/^([^:]+)::([^(]+)\(\):(\d+)$/', $closureInfo, $closureMatches)) {
$fullClass = $closureMatches[1];
$method = $closureMatches[2];
$line = $closureMatches[3];
// Entferne Namespace
$classParts = explode('\\', $fullClass);
$shortClass = end($classParts);
return sprintf('{closure:%s::%s():%s}', $shortClass, $method, $line);
}
// Fallback: einfach Namespaces entfernen
$closureInfo = preg_replace_callback(
'/([A-Z][a-zA-Z0-9_\\\\]*)/',
fn($m) => $this->removeNamespaceFromClass($m[0]),
fn ($m) => $this->removeNamespaceFromClass($m[0]),
$closureInfo
);
return sprintf('{closure:%s}', $closureInfo);
}
@@ -374,6 +386,7 @@ final readonly class StackItem
// Normalisiere Forward-Slashes zu Backslashes
$normalized = str_replace('/', '\\', $classString);
$parts = explode('\\', $normalized);
return end($parts);
}
@@ -403,6 +416,7 @@ final readonly class StackItem
$methodName = $this->formatFunctionName($this->function);
$separator = $this->type === '::' ? '::' : '->';
$paramsStr = $params !== '' ? $params : '';
return sprintf('%s%s%s(%s) in %s', $className, $separator, $methodName, $paramsStr, $location);
}
@@ -410,6 +424,7 @@ final readonly class StackItem
if ($this->function !== null) {
$methodName = $this->formatFunctionName($this->function);
$paramsStr = $params !== '' ? $params : '';
return sprintf('%s(%s) in %s', $methodName, $paramsStr, $location);
}
@@ -443,7 +458,7 @@ final readonly class StackItem
$data['type'] = $this->type;
}
if (!empty($this->args)) {
if (! empty($this->args)) {
$data['args'] = $this->serializeArgs();
}
@@ -458,7 +473,7 @@ final readonly class StackItem
private function serializeArgs(): array
{
return array_map(
fn($arg) => $this->formatValueForOutput($arg),
fn ($arg) => $this->formatValueForOutput($arg),
$this->args
);
}
@@ -484,6 +499,7 @@ final readonly class StackItem
}
$projectRoot = dirname(__DIR__, 4);
return $projectRoot;
}
}