Protokoll #7765

ID7765
Zeitstempel2025-12-23 08:32:27.888672
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuspending
Tokens1,612 (Input: 1,612, Output: 0)
Dauer-
Request-Zeit2025-12-23 08:32:27.888672
Response-Zeit-

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/opt\/scripts\/di-check.php",
        "content": "#!\/usr\/bin\/env php\n<?php\n\/**\n * DI Dependency Resolution Check\n *\n * Validates that all UseCase constructor dependencies can be resolved\n * by the DI Container (either via explicit registration or autowiring).\n *\n * Usage: php di-check.php [project-path]\n *\n * Exit codes:\n *   0 = All dependencies resolvable\n *   1 = Unresolvable dependencies found\n *\/\n\n\/\/ @responsibility: Prüft ob alle UseCase-Dependencies via DI auflösbar sind\n\ndeclare(strict_types=1);\n\n$projectDir = $argv[1] ?? '\/var\/www\/dev.campus.systemische-tools.de';\n$srcDir = $projectDir . '\/src';\n$servicesFile = $projectDir . '\/src\/services.php';\n\n\/\/ Colors for terminal output\n$RED = \"\\033[0;31m\";\n$GREEN = \"\\033[0;32m\";\n$YELLOW = \"\\033[1;33m\";\n$NC = \"\\033[0m\";\n\necho \"=== DI Dependency Resolution Check ===\\n\";\necho \"Project: $projectDir\\n\\n\";\n\n\/\/ Load autoloader\nrequire_once $projectDir . '\/vendor\/autoload.php';\n\n\/\/ Parse services.php to find registered services\nfunction getRegisteredServices(string $servicesFile): array {\n    $content = file_get_contents($servicesFile);\n    $registered = [];\n\n    \/\/ Match: $container->set(ClassName::class, ...)\n    preg_match_all('\/\\$container->set\\(([^:]+)::class\/', $content, $matches);\n\n    foreach ($matches[1] as $match) {\n        \/\/ Resolve the full class name from use statements\n        $className = trim($match);\n        $registered[$className] = true;\n    }\n\n    \/\/ Also parse use statements to get full class names\n    preg_match_all('\/^use\\s+([^;]+);\/m', $content, $useMatches);\n    $useMap = [];\n    foreach ($useMatches[1] as $use) {\n        $parts = explode('\\\\', $use);\n        $shortName = end($parts);\n        $useMap[$shortName] = $use;\n    }\n\n    \/\/ Build full class name map\n    $fullRegistered = [];\n    foreach ($registered as $short => $_) {\n        if (isset($useMap[$short])) {\n            $fullRegistered[$useMap[$short]] = true;\n        } else {\n            $fullRegistered[$short] = true;\n        }\n    }\n\n    return $fullRegistered;\n}\n\n\/\/ Get all UseCase files\nfunction getUseCaseFiles(string $srcDir): array {\n    $files = [];\n    $iterator = new RecursiveIteratorIterator(\n        new RecursiveDirectoryIterator($srcDir . '\/UseCases')\n    );\n\n    foreach ($iterator as $file) {\n        if ($file->isFile() && $file->getExtension() === 'php') {\n            $files[] = $file->getPathname();\n        }\n    }\n\n    return $files;\n}\n\n\/\/ Check if a dependency can be resolved\nfunction canResolve(string $dependency, array $registered): array {\n    \/\/ Check if explicitly registered\n    if (isset($registered[$dependency])) {\n        return ['resolvable' => true, 'method' => 'registered'];\n    }\n\n    \/\/ Check if it's an interface (must be registered)\n    if (str_ends_with($dependency, 'Interface')) {\n        return ['resolvable' => false, 'method' => 'interface_not_registered'];\n    }\n\n    \/\/ Check if class exists (can be autowired)\n    if (class_exists($dependency)) {\n        return ['resolvable' => true, 'method' => 'autowire'];\n    }\n\n    return ['resolvable' => false, 'method' => 'not_found'];\n}\n\n\/\/ Analyze a UseCase class\nfunction analyzeUseCase(string $file, array $registered): array {\n    $issues = [];\n\n    \/\/ Get class name from file\n    $content = file_get_contents($file);\n\n    \/\/ Extract namespace\n    preg_match('\/namespace\\s+([^;]+);\/', $content, $nsMatch);\n    $namespace = $nsMatch[1] ?? '';\n\n    \/\/ Extract class name\n    preg_match('\/class\\s+(\\w+)\/', $content, $classMatch);\n    $className = $classMatch[1] ?? '';\n\n    if (!$className) {\n        return [];\n    }\n\n    $fullClassName = $namespace . '\\\\' . $className;\n\n    \/\/ Skip if class doesn't exist (syntax error or not autoloadable)\n    if (!class_exists($fullClassName)) {\n        return [];\n    }\n\n    try {\n        $reflection = new ReflectionClass($fullClassName);\n        $constructor = $reflection->getConstructor();\n\n        if ($constructor === null) {\n            return [];\n        }\n\n        foreach ($constructor->getParameters() as $param) {\n            $type = $param->getType();\n\n            \/\/ Skip optional parameters with defaults\n            if ($param->isDefaultValueAvailable()) {\n                continue;\n            }\n\n            \/\/ Skip if no type hint\n            if ($type === null || !$type instanceof ReflectionNamedType) {\n                continue;\n            }\n\n            \/\/ Skip built-in types\n            if ($type->isBuiltin()) {\n                continue;\n            }\n\n            $typeName = $type->getName();\n            $result = canResolve($typeName, $registered);\n\n            if (!$result['resolvable']) {\n                $issues[] = [\n                    'class' => $fullClassName,\n                    'parameter' => $param->getName(),\n                    'type' => $typeName,\n                    'reason' => $result['method'],\n                ];\n            }\n        }\n    } catch (ReflectionException $e) {\n        \/\/ Skip if reflection fails\n    }\n\n    return $issues;\n}\n\n\/\/ Main execution\n$registered = getRegisteredServices($servicesFile);\n$useCaseFiles = getUseCaseFiles($srcDir);\n$allIssues = [];\n\necho \"Checking \" . count($useCaseFiles) . \" UseCase files...\\n\\n\";\n\nforeach ($useCaseFiles as $file) {\n    $issues = analyzeUseCase($file, $registered);\n    if (!empty($issues)) {\n        $allIssues = array_merge($allIssues, $issues);\n    }\n}\n\nif (empty($allIssues)) {\n    echo \"{$GREEN}✓ All UseCase dependencies are resolvable{$NC}\\n\";\n    echo \"\\nRegistered services: \" . count($registered) . \"\\n\";\n    echo \"UseCases checked: \" . count($useCaseFiles) . \"\\n\";\n    exit(0);\n} else {\n    echo \"{$RED}✗ Found \" . count($allIssues) . \" unresolvable dependencies:{$NC}\\n\\n\";\n\n    foreach ($allIssues as $issue) {\n        $shortClass = basename(str_replace('\\\\', '\/', $issue['class']));\n        echo \"  {$YELLOW}{$shortClass}{$NC}\\n\";\n        echo \"    Parameter: \\${$issue['parameter']}\\n\";\n        echo \"    Type: {$issue['type']}\\n\";\n        echo \"    Reason: {$issue['reason']}\\n\\n\";\n    }\n\n    echo \"Fix: Register missing interfaces in src\/services.php\\n\";\n    exit(1);\n}\n"
    }
}

Response

-
← Vorheriger Zur Liste Nächster →