Protokoll #11802
| ID | 11802 |
|---|---|
| Zeitstempel | 2025-12-23 21:42:41.063824 |
| Client | root |
| IP | Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 4,227 (Input: 0, Output: 0) |
| Dauer | 85 ms |
| Request-Zeit | Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18 |
| Response-Zeit | - |
Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22
Request
{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Infrastructure\/CodeAnalysis\/CodeQualityChecker.php",
"content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Infrastructure\\CodeAnalysis;\n\n\/\/ @responsibility: Code-Qualitätsanalyse (Hardcoded, Complexity, Metrics)\n\nfinal class CodeQualityChecker\n{\n \/** @var array<string, string> Regex patterns for hardcoded detection *\/\n private const HARDCODED_PATTERNS = [\n 'password' => '\/[\"\\'](?:password|passwd|pwd)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{3,}[\"\\']\/i',\n 'api_key' => '\/[\"\\'](?:api[_-]?key|apikey|secret[_-]?key)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{8,}[\"\\']\/i',\n 'token' => '\/[\"\\'](?:token|auth[_-]?token|access[_-]?token)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{8,}[\"\\']\/i',\n 'ip_address' => '\/[\"\\']\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}[\"\\']\/i',\n 'url_with_creds' => '\/https?:\\\\\/\\\\\/[^:]+:[^@]+@\/i',\n 'magic_number' => '\/(?<![\\\\w])(?:100|1000|60|24|365|3600|86400)(?![\\\\w])\/',\n ];\n\n \/** @var array<string, int> Thresholds for scoring *\/\n private const THRESHOLDS = [\n 'loc_excellent' => 100,\n 'loc_good' => 200,\n 'loc_acceptable' => 400,\n 'loc_poor' => 600,\n 'methods_excellent' => 5,\n 'methods_good' => 10,\n 'methods_acceptable' => 15,\n 'methods_poor' => 20,\n 'deps_excellent' => 3,\n 'deps_good' => 7,\n 'deps_acceptable' => 12,\n 'deps_poor' => 20,\n ];\n\n \/**\n * Analysiert eine Datei auf Qualitätsprobleme.\n *\n * @param array<string, mixed> $analysisData Daten aus code_analysis\n * @return array{\n * complexity_score: int,\n * loc_score: int,\n * dependency_score: int,\n * hardcoded_count: int,\n * issues_count: int,\n * warnings_count: int,\n * quality_grade: string,\n * issues_json: string\n * }\n *\/\n public function analyze(array $analysisData): array\n {\n $issues = [];\n $warnings = [];\n\n $filePath = $analysisData['file_path'] ?? '';\n $content = file_exists($filePath) ? file_get_contents($filePath) : '';\n\n \/\/ LOC Analysis\n $lineCount = $analysisData['line_count'] ?? 0;\n $locScore = $this->calculateLocScore($lineCount);\n if ($lineCount > self::THRESHOLDS['loc_poor']) {\n $issues[] = [\n 'type' => 'complexity',\n 'rule' => 'file-too-long',\n 'message' => \"Datei hat {$lineCount} Zeilen (max empfohlen: \" . self::THRESHOLDS['loc_acceptable'] . \")\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Method Count Analysis\n $functions = json_decode($analysisData['functions'] ?? '[]', true);\n $methodCount = is_array($functions) ? count($functions) : 0;\n $methodScore = $this->calculateMethodScore($methodCount);\n if ($methodCount > self::THRESHOLDS['methods_poor']) {\n $issues[] = [\n 'type' => 'srp',\n 'rule' => 'too-many-methods',\n 'message' => \"Klasse hat {$methodCount} Methoden (SRP-Verletzung möglich)\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Dependency Analysis\n $uses = json_decode($analysisData['uses'] ?? '[]', true);\n $depsCount = is_array($uses) ? count($uses) : 0;\n $depScore = $this->calculateDependencyScore($depsCount);\n if ($depsCount > self::THRESHOLDS['deps_poor']) {\n $issues[] = [\n 'type' => 'coupling',\n 'rule' => 'too-many-dependencies',\n 'message' => \"Klasse hat {$depsCount} Dependencies (hohe Kopplung)\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Hardcoded Detection\n $hardcodedIssues = $this->detectHardcoded($content, $filePath);\n $hardcodedCount = count($hardcodedIssues);\n $issues = array_merge($issues, $hardcodedIssues);\n\n \/\/ Calculate complexity score (weighted average)\n $complexityScore = (int) (($locScore * 0.3 + $methodScore * 0.3 + $depScore * 0.4));\n\n \/\/ Penalize for hardcoded values\n $complexityScore = max(0, $complexityScore - ($hardcodedCount * 10));\n\n \/\/ Determine grade\n $totalIssues = count($issues);\n $totalWarnings = count(array_filter($issues, fn($i) => ($i['severity'] ?? '') === 'warning'));\n $grade = $this->calculateGrade($complexityScore, $totalIssues);\n\n return [\n 'complexity_score' => $complexityScore,\n 'loc_score' => $locScore,\n 'dependency_score' => $depScore,\n 'hardcoded_count' => $hardcodedCount,\n 'issues_count' => $totalIssues,\n 'warnings_count' => $totalWarnings,\n 'quality_grade' => $grade,\n 'issues_json' => json_encode($issues, JSON_UNESCAPED_UNICODE),\n ];\n }\n\n private function calculateLocScore(int $loc): int\n {\n if ($loc <= self::THRESHOLDS['loc_excellent']) {\n return 100;\n }\n if ($loc <= self::THRESHOLDS['loc_good']) {\n return 80;\n }\n if ($loc <= self::THRESHOLDS['loc_acceptable']) {\n return 60;\n }\n if ($loc <= self::THRESHOLDS['loc_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n private function calculateMethodScore(int $count): int\n {\n if ($count <= self::THRESHOLDS['methods_excellent']) {\n return 100;\n }\n if ($count <= self::THRESHOLDS['methods_good']) {\n return 80;\n }\n if ($count <= self::THRESHOLDS['methods_acceptable']) {\n return 60;\n }\n if ($count <= self::THRESHOLDS['methods_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n private function calculateDependencyScore(int $count): int\n {\n if ($count <= self::THRESHOLDS['deps_excellent']) {\n return 100;\n }\n if ($count <= self::THRESHOLDS['deps_good']) {\n return 80;\n }\n if ($count <= self::THRESHOLDS['deps_acceptable']) {\n return 60;\n }\n if ($count <= self::THRESHOLDS['deps_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n \/**\n * @return array<array{type: string, rule: string, message: string, severity: string, line?: int}>\n *\/\n private function detectHardcoded(string $content, string $filePath): array\n {\n $issues = [];\n\n \/\/ Skip config files and test files\n $filename = basename($filePath);\n if (preg_match('\/^(config|\\.env|test|spec)\/i', $filename)) {\n return [];\n }\n\n foreach (self::HARDCODED_PATTERNS as $type => $pattern) {\n \/\/ Skip magic numbers in config\/constant files\n if ($type === 'magic_number' && preg_match('\/const|config\/i', $filePath)) {\n continue;\n }\n\n if (preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) {\n foreach ($matches[0] as $match) {\n $line = substr_count(substr($content, 0, $match[1]), \"\\n\") + 1;\n $issues[] = [\n 'type' => 'hardcoded',\n 'rule' => \"hardcoded-{$type}\",\n 'message' => \"Möglicher hardcoded {$type}: \" . substr($match[0], 0, 30) . '...',\n 'severity' => $type === 'magic_number' ? 'info' : 'warning',\n 'line' => $line,\n ];\n }\n }\n }\n\n return $issues;\n }\n\n private function calculateGrade(int $score, int $issueCount): string\n {\n \/\/ Penalize for issues\n $adjustedScore = $score - ($issueCount * 5);\n\n if ($adjustedScore >= 90) {\n return 'A';\n }\n if ($adjustedScore >= 75) {\n return 'B';\n }\n if ($adjustedScore >= 60) {\n return 'C';\n }\n if ($adjustedScore >= 40) {\n return 'D';\n }\n\n return 'F';\n }\n}\n"
}
}
Response
{
"tool_response": {
"type": "create",
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Infrastructure\/CodeAnalysis\/CodeQualityChecker.php",
"content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Infrastructure\\CodeAnalysis;\n\n\/\/ @responsibility: Code-Qualitätsanalyse (Hardcoded, Complexity, Metrics)\n\nfinal class CodeQualityChecker\n{\n \/** @var array<string, string> Regex patterns for hardcoded detection *\/\n private const HARDCODED_PATTERNS = [\n 'password' => '\/[\"\\'](?:password|passwd|pwd)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{3,}[\"\\']\/i',\n 'api_key' => '\/[\"\\'](?:api[_-]?key|apikey|secret[_-]?key)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{8,}[\"\\']\/i',\n 'token' => '\/[\"\\'](?:token|auth[_-]?token|access[_-]?token)[\"\\']\\\\s*[=:]\\\\s*[\"\\'][^\"\\']{8,}[\"\\']\/i',\n 'ip_address' => '\/[\"\\']\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}[\"\\']\/i',\n 'url_with_creds' => '\/https?:\\\\\/\\\\\/[^:]+:[^@]+@\/i',\n 'magic_number' => '\/(?<![\\\\w])(?:100|1000|60|24|365|3600|86400)(?![\\\\w])\/',\n ];\n\n \/** @var array<string, int> Thresholds for scoring *\/\n private const THRESHOLDS = [\n 'loc_excellent' => 100,\n 'loc_good' => 200,\n 'loc_acceptable' => 400,\n 'loc_poor' => 600,\n 'methods_excellent' => 5,\n 'methods_good' => 10,\n 'methods_acceptable' => 15,\n 'methods_poor' => 20,\n 'deps_excellent' => 3,\n 'deps_good' => 7,\n 'deps_acceptable' => 12,\n 'deps_poor' => 20,\n ];\n\n \/**\n * Analysiert eine Datei auf Qualitätsprobleme.\n *\n * @param array<string, mixed> $analysisData Daten aus code_analysis\n * @return array{\n * complexity_score: int,\n * loc_score: int,\n * dependency_score: int,\n * hardcoded_count: int,\n * issues_count: int,\n * warnings_count: int,\n * quality_grade: string,\n * issues_json: string\n * }\n *\/\n public function analyze(array $analysisData): array\n {\n $issues = [];\n $warnings = [];\n\n $filePath = $analysisData['file_path'] ?? '';\n $content = file_exists($filePath) ? file_get_contents($filePath) : '';\n\n \/\/ LOC Analysis\n $lineCount = $analysisData['line_count'] ?? 0;\n $locScore = $this->calculateLocScore($lineCount);\n if ($lineCount > self::THRESHOLDS['loc_poor']) {\n $issues[] = [\n 'type' => 'complexity',\n 'rule' => 'file-too-long',\n 'message' => \"Datei hat {$lineCount} Zeilen (max empfohlen: \" . self::THRESHOLDS['loc_acceptable'] . \")\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Method Count Analysis\n $functions = json_decode($analysisData['functions'] ?? '[]', true);\n $methodCount = is_array($functions) ? count($functions) : 0;\n $methodScore = $this->calculateMethodScore($methodCount);\n if ($methodCount > self::THRESHOLDS['methods_poor']) {\n $issues[] = [\n 'type' => 'srp',\n 'rule' => 'too-many-methods',\n 'message' => \"Klasse hat {$methodCount} Methoden (SRP-Verletzung möglich)\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Dependency Analysis\n $uses = json_decode($analysisData['uses'] ?? '[]', true);\n $depsCount = is_array($uses) ? count($uses) : 0;\n $depScore = $this->calculateDependencyScore($depsCount);\n if ($depsCount > self::THRESHOLDS['deps_poor']) {\n $issues[] = [\n 'type' => 'coupling',\n 'rule' => 'too-many-dependencies',\n 'message' => \"Klasse hat {$depsCount} Dependencies (hohe Kopplung)\",\n 'severity' => 'warning',\n ];\n }\n\n \/\/ Hardcoded Detection\n $hardcodedIssues = $this->detectHardcoded($content, $filePath);\n $hardcodedCount = count($hardcodedIssues);\n $issues = array_merge($issues, $hardcodedIssues);\n\n \/\/ Calculate complexity score (weighted average)\n $complexityScore = (int) (($locScore * 0.3 + $methodScore * 0.3 + $depScore * 0.4));\n\n \/\/ Penalize for hardcoded values\n $complexityScore = max(0, $complexityScore - ($hardcodedCount * 10));\n\n \/\/ Determine grade\n $totalIssues = count($issues);\n $totalWarnings = count(array_filter($issues, fn($i) => ($i['severity'] ?? '') === 'warning'));\n $grade = $this->calculateGrade($complexityScore, $totalIssues);\n\n return [\n 'complexity_score' => $complexityScore,\n 'loc_score' => $locScore,\n 'dependency_score' => $depScore,\n 'hardcoded_count' => $hardcodedCount,\n 'issues_count' => $totalIssues,\n 'warnings_count' => $totalWarnings,\n 'quality_grade' => $grade,\n 'issues_json' => json_encode($issues, JSON_UNESCAPED_UNICODE),\n ];\n }\n\n private function calculateLocScore(int $loc): int\n {\n if ($loc <= self::THRESHOLDS['loc_excellent']) {\n return 100;\n }\n if ($loc <= self::THRESHOLDS['loc_good']) {\n return 80;\n }\n if ($loc <= self::THRESHOLDS['loc_acceptable']) {\n return 60;\n }\n if ($loc <= self::THRESHOLDS['loc_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n private function calculateMethodScore(int $count): int\n {\n if ($count <= self::THRESHOLDS['methods_excellent']) {\n return 100;\n }\n if ($count <= self::THRESHOLDS['methods_good']) {\n return 80;\n }\n if ($count <= self::THRESHOLDS['methods_acceptable']) {\n return 60;\n }\n if ($count <= self::THRESHOLDS['methods_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n private function calculateDependencyScore(int $count): int\n {\n if ($count <= self::THRESHOLDS['deps_excellent']) {\n return 100;\n }\n if ($count <= self::THRESHOLDS['deps_good']) {\n return 80;\n }\n if ($count <= self::THRESHOLDS['deps_acceptable']) {\n return 60;\n }\n if ($count <= self::THRESHOLDS['deps_poor']) {\n return 40;\n }\n\n return 20;\n }\n\n \/**\n * @return array<array{type: string, rule: string, message: string, severity: string, line?: int}>\n *\/\n private function detectHardcoded(string $content, string $filePath): array\n {\n $issues = [];\n\n \/\/ Skip config files and test files\n $filename = basename($filePath);\n if (preg_match('\/^(config|\\.env|test|spec)\/i', $filename)) {\n return [];\n }\n\n foreach (self::HARDCODED_PATTERNS as $type => $pattern) {\n \/\/ Skip magic numbers in config\/constant files\n if ($type === 'magic_number' && preg_match('\/const|config\/i', $filePath)) {\n continue;\n }\n\n if (preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) {\n foreach ($matches[0] as $match) {\n $line = substr_count(substr($content, 0, $match[1]), \"\\n\") + 1;\n $issues[] = [\n 'type' => 'hardcoded',\n 'rule' => \"hardcoded-{$type}\",\n 'message' => \"Möglicher hardcoded {$type}: \" . substr($match[0], 0, 30) . '...',\n 'severity' => $type === 'magic_number' ? 'info' : 'warning',\n 'line' => $line,\n ];\n }\n }\n }\n\n return $issues;\n }\n\n private function calculateGrade(int $score, int $issueCount): string\n {\n \/\/ Penalize for issues\n $adjustedScore = $score - ($issueCount * 5);\n\n if ($adjustedScore >= 90) {\n return 'A';\n }\n if ($adjustedScore >= 75) {\n return 'B';\n }\n if ($adjustedScore >= 60) {\n return 'C';\n }\n if ($adjustedScore >= 40) {\n return 'D';\n }\n\n return 'F';\n }\n}\n",
"structuredPatch": [],
"originalFile": null
}
}