{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/opt\/scripts\/di-check.sh",
"content": "#!\/bin\/bash\n# DI Dependency Resolution Check\n# Validates that all UseCase constructor dependencies can be resolved\n# by the DI Container (either via explicit registration or autowiring).\n#\n# Usage: di-check.sh [project-path]\n#\n# Exit codes:\n# 0 = All dependencies resolvable\n# 1 = Unresolvable dependencies found\n\nPROJECT_DIR=\"${1:-\/var\/www\/dev.campus.systemische-tools.de}\"\n\nphp -r '\n$projectDir = $argv[1];\n$srcDir = $projectDir . \"\/src\";\n$servicesFile = $projectDir . \"\/src\/services.php\";\n\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\nrequire_once $projectDir . \"\/vendor\/autoload.php\";\n\nfunction getRegisteredServices(string $servicesFile): array {\n $content = file_get_contents($servicesFile);\n $registered = [];\n preg_match_all(\"\/\\\\\\$container->set\\\\(([^:]+)::class\/\", $content, $matches);\n foreach ($matches[1] as $match) {\n $registered[trim($match)] = true;\n }\n preg_match_all(\"\/^use\\\\s+([^;]+);\/m\", $content, $useMatches);\n $useMap = [];\n foreach ($useMatches[1] as $use) {\n $parts = explode(\"\\\\\\\\\", $use);\n $useMap[end($parts)] = $use;\n }\n $fullRegistered = [];\n foreach ($registered as $short => $_) {\n $fullRegistered[$useMap[$short] ?? $short] = true;\n }\n return $fullRegistered;\n}\n\nfunction getUseCaseFiles(string $srcDir): array {\n $files = [];\n $iterator = new RecursiveIteratorIterator(\n new RecursiveDirectoryIterator($srcDir . \"\/UseCases\")\n );\n foreach ($iterator as $file) {\n if ($file->isFile() && $file->getExtension() === \"php\") {\n $files[] = $file->getPathname();\n }\n }\n return $files;\n}\n\nfunction canResolve(string $dependency, array $registered): array {\n if (isset($registered[$dependency])) {\n return [\"resolvable\" => true, \"method\" => \"registered\"];\n }\n if (str_ends_with($dependency, \"Interface\")) {\n return [\"resolvable\" => false, \"method\" => \"interface_not_registered\"];\n }\n if (class_exists($dependency)) {\n return [\"resolvable\" => true, \"method\" => \"autowire\"];\n }\n return [\"resolvable\" => false, \"method\" => \"not_found\"];\n}\n\nfunction analyzeUseCase(string $file, array $registered): array {\n $issues = [];\n $content = file_get_contents($file);\n preg_match(\"\/namespace\\\\s+([^;]+);\/\", $content, $nsMatch);\n $namespace = $nsMatch[1] ?? \"\";\n preg_match(\"\/class\\\\s+(\\\\w+)\/\", $content, $classMatch);\n $className = $classMatch[1] ?? \"\";\n if (!$className) return [];\n $fullClassName = $namespace . \"\\\\\\\\\" . $className;\n if (!class_exists($fullClassName)) return [];\n try {\n $reflection = new ReflectionClass($fullClassName);\n $constructor = $reflection->getConstructor();\n if ($constructor === null) return [];\n foreach ($constructor->getParameters() as $param) {\n $type = $param->getType();\n if ($param->isDefaultValueAvailable()) continue;\n if ($type === null || !$type instanceof ReflectionNamedType) continue;\n if ($type->isBuiltin()) continue;\n $typeName = $type->getName();\n $result = canResolve($typeName, $registered);\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 return $issues;\n}\n\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 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 echo \"Fix: Register missing interfaces in src\/services.php\\n\";\n exit(1);\n}\n' -- \"$PROJECT_DIR\"\n"
}
}
{
"tool_response": {
"type": "create",
"filePath": "\/opt\/scripts\/di-check.sh",
"content": "#!\/bin\/bash\n# DI Dependency Resolution Check\n# Validates that all UseCase constructor dependencies can be resolved\n# by the DI Container (either via explicit registration or autowiring).\n#\n# Usage: di-check.sh [project-path]\n#\n# Exit codes:\n# 0 = All dependencies resolvable\n# 1 = Unresolvable dependencies found\n\nPROJECT_DIR=\"${1:-\/var\/www\/dev.campus.systemische-tools.de}\"\n\nphp -r '\n$projectDir = $argv[1];\n$srcDir = $projectDir . \"\/src\";\n$servicesFile = $projectDir . \"\/src\/services.php\";\n\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\nrequire_once $projectDir . \"\/vendor\/autoload.php\";\n\nfunction getRegisteredServices(string $servicesFile): array {\n $content = file_get_contents($servicesFile);\n $registered = [];\n preg_match_all(\"\/\\\\\\$container->set\\\\(([^:]+)::class\/\", $content, $matches);\n foreach ($matches[1] as $match) {\n $registered[trim($match)] = true;\n }\n preg_match_all(\"\/^use\\\\s+([^;]+);\/m\", $content, $useMatches);\n $useMap = [];\n foreach ($useMatches[1] as $use) {\n $parts = explode(\"\\\\\\\\\", $use);\n $useMap[end($parts)] = $use;\n }\n $fullRegistered = [];\n foreach ($registered as $short => $_) {\n $fullRegistered[$useMap[$short] ?? $short] = true;\n }\n return $fullRegistered;\n}\n\nfunction getUseCaseFiles(string $srcDir): array {\n $files = [];\n $iterator = new RecursiveIteratorIterator(\n new RecursiveDirectoryIterator($srcDir . \"\/UseCases\")\n );\n foreach ($iterator as $file) {\n if ($file->isFile() && $file->getExtension() === \"php\") {\n $files[] = $file->getPathname();\n }\n }\n return $files;\n}\n\nfunction canResolve(string $dependency, array $registered): array {\n if (isset($registered[$dependency])) {\n return [\"resolvable\" => true, \"method\" => \"registered\"];\n }\n if (str_ends_with($dependency, \"Interface\")) {\n return [\"resolvable\" => false, \"method\" => \"interface_not_registered\"];\n }\n if (class_exists($dependency)) {\n return [\"resolvable\" => true, \"method\" => \"autowire\"];\n }\n return [\"resolvable\" => false, \"method\" => \"not_found\"];\n}\n\nfunction analyzeUseCase(string $file, array $registered): array {\n $issues = [];\n $content = file_get_contents($file);\n preg_match(\"\/namespace\\\\s+([^;]+);\/\", $content, $nsMatch);\n $namespace = $nsMatch[1] ?? \"\";\n preg_match(\"\/class\\\\s+(\\\\w+)\/\", $content, $classMatch);\n $className = $classMatch[1] ?? \"\";\n if (!$className) return [];\n $fullClassName = $namespace . \"\\\\\\\\\" . $className;\n if (!class_exists($fullClassName)) return [];\n try {\n $reflection = new ReflectionClass($fullClassName);\n $constructor = $reflection->getConstructor();\n if ($constructor === null) return [];\n foreach ($constructor->getParameters() as $param) {\n $type = $param->getType();\n if ($param->isDefaultValueAvailable()) continue;\n if ($type === null || !$type instanceof ReflectionNamedType) continue;\n if ($type->isBuiltin()) continue;\n $typeName = $type->getName();\n $result = canResolve($typeName, $registered);\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 return $issues;\n}\n\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 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 echo \"Fix: Register missing interfaces in src\/services.php\\n\";\n exit(1);\n}\n' -- \"$PROJECT_DIR\"\n",
"structuredPatch": [],
"originalFile": null
}
}