Protokoll #3375

ID3375
Zeitstempel2025-12-22 07:57:47.823706
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens4,385 (Input: 2,190, Output: 2,195)
Dauer89 ms
Request-Zeit2025-12-22 07:57:47.823706
Response-Zeit2025-12-22 07:57:47.912635

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/CriticsController.php",
        "content": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Config\\DatabaseFactory;\n\nclass CriticsController extends Controller\n{\n    private \\PDO $db;\n\n    public function __construct()\n    {\n        $this->db = DatabaseFactory::content();\n    }\n\n    \/**\n     * GET \/critics\n     *\/\n    public function index(): void\n    {\n        $stmt = $this->db->query('\n            SELECT c.*, p.name as prompt_name\n            FROM critics c\n            LEFT JOIN prompts p ON c.prompt_id = p.id\n            ORDER BY c.sort_order, c.name\n        ');\n        $critics = $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n\n        $stats = $this->getStatistics();\n\n        $this->view('critics.index', [\n            'title' => 'Critics verwalten',\n            'critics' => $critics,\n            'stats' => $stats,\n        ]);\n    }\n\n    \/**\n     * GET \/critics\/new\n     *\/\n    public function criticsNew(): void\n    {\n        $prompts = $this->getAvailablePrompts();\n\n        $this->view('critics.form', [\n            'title' => 'Neuer Critic',\n            'critic' => null,\n            'prompts' => $prompts,\n            'isEdit' => false,\n        ]);\n    }\n\n    \/**\n     * POST \/critics\n     *\/\n    public function store(): void\n    {\n        $this->requireCsrf();\n\n        $name = trim($_POST['name'] ?? '');\n        $fokus = $_POST['fokus'] ?? '';\n        $promptId = !empty($_POST['prompt_id']) ? (int) $_POST['prompt_id'] : null;\n        $sortOrder = (int) ($_POST['sort_order'] ?? 0);\n        $isActive = isset($_POST['is_active']) ? 1 : 0;\n\n        if ($name === '') {\n            $_SESSION['error'] = 'Name ist erforderlich.';\n            header('Location: \/critics\/new');\n            exit;\n        }\n\n        \/\/ Fokus als JSON Array speichern\n        $fokusArray = array_filter(array_map('trim', explode(\"\\n\", $fokus)));\n        $fokusJson = json_encode(array_values($fokusArray), JSON_UNESCAPED_UNICODE);\n\n        $stmt = $this->db->prepare('\n            INSERT INTO critics (name, fokus, prompt_id, sort_order, is_active)\n            VALUES (?, ?, ?, ?, ?)\n        ');\n        $stmt->execute([$name, $fokusJson, $promptId, $sortOrder, $isActive]);\n        $id = $this->db->lastInsertId();\n\n        $_SESSION['success'] = 'Critic erfolgreich erstellt.';\n        header('Location: \/critics\/' . $id);\n        exit;\n    }\n\n    \/**\n     * GET \/critics\/{id}\n     *\/\n    public function show(string $id): void\n    {\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        \/\/ Prompt-Details laden\n        $prompt = null;\n        if ($critic['prompt_id']) {\n            $stmt = $this->db->prepare('SELECT * FROM prompts WHERE id = ?');\n            $stmt->execute([$critic['prompt_id']]);\n            $prompt = $stmt->fetch(\\PDO::FETCH_ASSOC);\n        }\n\n        \/\/ Letzte Critiques anzeigen\n        $stmt = $this->db->prepare('\n            SELECT cc.*, cv.version_number, co.title as order_title\n            FROM content_critiques cc\n            JOIN content_versions cv ON cc.version_id = cv.id\n            JOIN content_orders co ON cv.order_id = co.id\n            WHERE cc.critic_id = ?\n            ORDER BY cc.created_at DESC\n            LIMIT 10\n        ');\n        $stmt->execute([$id]);\n        $recentCritiques = $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n\n        $this->view('critics.show', [\n            'title' => $critic['name'],\n            'critic' => $critic,\n            'prompt' => $prompt,\n            'recentCritiques' => $recentCritiques,\n        ]);\n    }\n\n    \/**\n     * GET \/critics\/{id}\/edit\n     *\/\n    public function edit(string $id): void\n    {\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $prompts = $this->getAvailablePrompts();\n\n        $this->view('critics.form', [\n            'title' => 'Bearbeiten: ' . $critic['name'],\n            'critic' => $critic,\n            'prompts' => $prompts,\n            'isEdit' => true,\n        ]);\n    }\n\n    \/**\n     * POST \/critics\/{id}\n     *\/\n    public function update(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $name = trim($_POST['name'] ?? '');\n        $fokus = $_POST['fokus'] ?? '';\n        $promptId = !empty($_POST['prompt_id']) ? (int) $_POST['prompt_id'] : null;\n        $sortOrder = (int) ($_POST['sort_order'] ?? 0);\n        $isActive = isset($_POST['is_active']) ? 1 : 0;\n\n        if ($name === '') {\n            $_SESSION['error'] = 'Name ist erforderlich.';\n            header('Location: \/critics\/' . $id . '\/edit');\n            exit;\n        }\n\n        \/\/ Fokus als JSON Array speichern\n        $fokusArray = array_filter(array_map('trim', explode(\"\\n\", $fokus)));\n        $fokusJson = json_encode(array_values($fokusArray), JSON_UNESCAPED_UNICODE);\n\n        $stmt = $this->db->prepare('\n            UPDATE critics\n            SET name = ?, fokus = ?, prompt_id = ?, sort_order = ?, is_active = ?\n            WHERE id = ?\n        ');\n        $stmt->execute([$name, $fokusJson, $promptId, $sortOrder, $isActive, $id]);\n\n        $_SESSION['success'] = 'Critic aktualisiert.';\n        header('Location: \/critics\/' . $id);\n        exit;\n    }\n\n    \/**\n     * POST \/critics\/{id}\/delete\n     *\/\n    public function delete(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        \/\/ Prüfen ob Critiques existieren\n        $stmt = $this->db->prepare('SELECT COUNT(*) FROM content_critiques WHERE critic_id = ?');\n        $stmt->execute([$id]);\n        $critiqueCount = (int) $stmt->fetchColumn();\n\n        if ($critiqueCount > 0) {\n            $_SESSION['error'] = \"Kann nicht gelöscht werden: {$critiqueCount} Critiques verknüpft.\";\n            header('Location: \/critics\/' . $id);\n            exit;\n        }\n\n        $stmt = $this->db->prepare('DELETE FROM critics WHERE id = ?');\n        $stmt->execute([$id]);\n\n        $_SESSION['success'] = 'Critic gelöscht.';\n        header('Location: \/critics');\n        exit;\n    }\n\n    \/**\n     * POST \/critics\/{id}\/toggle\n     *\/\n    public function toggle(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $newStatus = $critic['is_active'] ? 0 : 1;\n        $stmt = $this->db->prepare('UPDATE critics SET is_active = ? WHERE id = ?');\n        $stmt->execute([$newStatus, $id]);\n\n        $statusText = $newStatus ? 'aktiviert' : 'deaktiviert';\n        $_SESSION['success'] = \"Critic {$statusText}.\";\n        header('Location: \/critics');\n        exit;\n    }\n\n    \/\/ ========== Private Helpers ==========\n\n    private function findById(int $id): ?array\n    {\n        $stmt = $this->db->prepare('\n            SELECT c.*, p.name as prompt_name\n            FROM critics c\n            LEFT JOIN prompts p ON c.prompt_id = p.id\n            WHERE c.id = ?\n        ');\n        $stmt->execute([$id]);\n        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);\n\n        return $result !== false ? $result : null;\n    }\n\n    private function getAvailablePrompts(): array\n    {\n        $stmt = $this->db->query('\n            SELECT id, name, version\n            FROM prompts\n            WHERE is_active = 1\n            ORDER BY name\n        ');\n\n        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n    }\n\n    private function getStatistics(): array\n    {\n        $stats = ['total' => 0, 'active' => 0, 'inactive' => 0, 'total_critiques' => 0];\n\n        $stmt = $this->db->query('SELECT COUNT(*) as cnt, SUM(is_active) as active FROM critics');\n        $row = $stmt->fetch(\\PDO::FETCH_ASSOC);\n        $stats['total'] = (int) $row['cnt'];\n        $stats['active'] = (int) $row['active'];\n        $stats['inactive'] = $stats['total'] - $stats['active'];\n\n        $stmt = $this->db->query('SELECT COUNT(*) FROM content_critiques');\n        $stats['total_critiques'] = (int) $stmt->fetchColumn();\n\n        return $stats;\n    }\n}\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/CriticsController.php",
        "content": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Config\\DatabaseFactory;\n\nclass CriticsController extends Controller\n{\n    private \\PDO $db;\n\n    public function __construct()\n    {\n        $this->db = DatabaseFactory::content();\n    }\n\n    \/**\n     * GET \/critics\n     *\/\n    public function index(): void\n    {\n        $stmt = $this->db->query('\n            SELECT c.*, p.name as prompt_name\n            FROM critics c\n            LEFT JOIN prompts p ON c.prompt_id = p.id\n            ORDER BY c.sort_order, c.name\n        ');\n        $critics = $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n\n        $stats = $this->getStatistics();\n\n        $this->view('critics.index', [\n            'title' => 'Critics verwalten',\n            'critics' => $critics,\n            'stats' => $stats,\n        ]);\n    }\n\n    \/**\n     * GET \/critics\/new\n     *\/\n    public function criticsNew(): void\n    {\n        $prompts = $this->getAvailablePrompts();\n\n        $this->view('critics.form', [\n            'title' => 'Neuer Critic',\n            'critic' => null,\n            'prompts' => $prompts,\n            'isEdit' => false,\n        ]);\n    }\n\n    \/**\n     * POST \/critics\n     *\/\n    public function store(): void\n    {\n        $this->requireCsrf();\n\n        $name = trim($_POST['name'] ?? '');\n        $fokus = $_POST['fokus'] ?? '';\n        $promptId = !empty($_POST['prompt_id']) ? (int) $_POST['prompt_id'] : null;\n        $sortOrder = (int) ($_POST['sort_order'] ?? 0);\n        $isActive = isset($_POST['is_active']) ? 1 : 0;\n\n        if ($name === '') {\n            $_SESSION['error'] = 'Name ist erforderlich.';\n            header('Location: \/critics\/new');\n            exit;\n        }\n\n        \/\/ Fokus als JSON Array speichern\n        $fokusArray = array_filter(array_map('trim', explode(\"\\n\", $fokus)));\n        $fokusJson = json_encode(array_values($fokusArray), JSON_UNESCAPED_UNICODE);\n\n        $stmt = $this->db->prepare('\n            INSERT INTO critics (name, fokus, prompt_id, sort_order, is_active)\n            VALUES (?, ?, ?, ?, ?)\n        ');\n        $stmt->execute([$name, $fokusJson, $promptId, $sortOrder, $isActive]);\n        $id = $this->db->lastInsertId();\n\n        $_SESSION['success'] = 'Critic erfolgreich erstellt.';\n        header('Location: \/critics\/' . $id);\n        exit;\n    }\n\n    \/**\n     * GET \/critics\/{id}\n     *\/\n    public function show(string $id): void\n    {\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        \/\/ Prompt-Details laden\n        $prompt = null;\n        if ($critic['prompt_id']) {\n            $stmt = $this->db->prepare('SELECT * FROM prompts WHERE id = ?');\n            $stmt->execute([$critic['prompt_id']]);\n            $prompt = $stmt->fetch(\\PDO::FETCH_ASSOC);\n        }\n\n        \/\/ Letzte Critiques anzeigen\n        $stmt = $this->db->prepare('\n            SELECT cc.*, cv.version_number, co.title as order_title\n            FROM content_critiques cc\n            JOIN content_versions cv ON cc.version_id = cv.id\n            JOIN content_orders co ON cv.order_id = co.id\n            WHERE cc.critic_id = ?\n            ORDER BY cc.created_at DESC\n            LIMIT 10\n        ');\n        $stmt->execute([$id]);\n        $recentCritiques = $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n\n        $this->view('critics.show', [\n            'title' => $critic['name'],\n            'critic' => $critic,\n            'prompt' => $prompt,\n            'recentCritiques' => $recentCritiques,\n        ]);\n    }\n\n    \/**\n     * GET \/critics\/{id}\/edit\n     *\/\n    public function edit(string $id): void\n    {\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $prompts = $this->getAvailablePrompts();\n\n        $this->view('critics.form', [\n            'title' => 'Bearbeiten: ' . $critic['name'],\n            'critic' => $critic,\n            'prompts' => $prompts,\n            'isEdit' => true,\n        ]);\n    }\n\n    \/**\n     * POST \/critics\/{id}\n     *\/\n    public function update(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $name = trim($_POST['name'] ?? '');\n        $fokus = $_POST['fokus'] ?? '';\n        $promptId = !empty($_POST['prompt_id']) ? (int) $_POST['prompt_id'] : null;\n        $sortOrder = (int) ($_POST['sort_order'] ?? 0);\n        $isActive = isset($_POST['is_active']) ? 1 : 0;\n\n        if ($name === '') {\n            $_SESSION['error'] = 'Name ist erforderlich.';\n            header('Location: \/critics\/' . $id . '\/edit');\n            exit;\n        }\n\n        \/\/ Fokus als JSON Array speichern\n        $fokusArray = array_filter(array_map('trim', explode(\"\\n\", $fokus)));\n        $fokusJson = json_encode(array_values($fokusArray), JSON_UNESCAPED_UNICODE);\n\n        $stmt = $this->db->prepare('\n            UPDATE critics\n            SET name = ?, fokus = ?, prompt_id = ?, sort_order = ?, is_active = ?\n            WHERE id = ?\n        ');\n        $stmt->execute([$name, $fokusJson, $promptId, $sortOrder, $isActive, $id]);\n\n        $_SESSION['success'] = 'Critic aktualisiert.';\n        header('Location: \/critics\/' . $id);\n        exit;\n    }\n\n    \/**\n     * POST \/critics\/{id}\/delete\n     *\/\n    public function delete(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        \/\/ Prüfen ob Critiques existieren\n        $stmt = $this->db->prepare('SELECT COUNT(*) FROM content_critiques WHERE critic_id = ?');\n        $stmt->execute([$id]);\n        $critiqueCount = (int) $stmt->fetchColumn();\n\n        if ($critiqueCount > 0) {\n            $_SESSION['error'] = \"Kann nicht gelöscht werden: {$critiqueCount} Critiques verknüpft.\";\n            header('Location: \/critics\/' . $id);\n            exit;\n        }\n\n        $stmt = $this->db->prepare('DELETE FROM critics WHERE id = ?');\n        $stmt->execute([$id]);\n\n        $_SESSION['success'] = 'Critic gelöscht.';\n        header('Location: \/critics');\n        exit;\n    }\n\n    \/**\n     * POST \/critics\/{id}\/toggle\n     *\/\n    public function toggle(string $id): void\n    {\n        $this->requireCsrf();\n\n        $critic = $this->findById((int) $id);\n\n        if ($critic === null) {\n            $this->notFound('Critic nicht gefunden');\n        }\n\n        $newStatus = $critic['is_active'] ? 0 : 1;\n        $stmt = $this->db->prepare('UPDATE critics SET is_active = ? WHERE id = ?');\n        $stmt->execute([$newStatus, $id]);\n\n        $statusText = $newStatus ? 'aktiviert' : 'deaktiviert';\n        $_SESSION['success'] = \"Critic {$statusText}.\";\n        header('Location: \/critics');\n        exit;\n    }\n\n    \/\/ ========== Private Helpers ==========\n\n    private function findById(int $id): ?array\n    {\n        $stmt = $this->db->prepare('\n            SELECT c.*, p.name as prompt_name\n            FROM critics c\n            LEFT JOIN prompts p ON c.prompt_id = p.id\n            WHERE c.id = ?\n        ');\n        $stmt->execute([$id]);\n        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);\n\n        return $result !== false ? $result : null;\n    }\n\n    private function getAvailablePrompts(): array\n    {\n        $stmt = $this->db->query('\n            SELECT id, name, version\n            FROM prompts\n            WHERE is_active = 1\n            ORDER BY name\n        ');\n\n        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n    }\n\n    private function getStatistics(): array\n    {\n        $stats = ['total' => 0, 'active' => 0, 'inactive' => 0, 'total_critiques' => 0];\n\n        $stmt = $this->db->query('SELECT COUNT(*) as cnt, SUM(is_active) as active FROM critics');\n        $row = $stmt->fetch(\\PDO::FETCH_ASSOC);\n        $stats['total'] = (int) $row['cnt'];\n        $stats['active'] = (int) $row['active'];\n        $stats['inactive'] = $stats['total'] - $stats['active'];\n\n        $stmt = $this->db->query('SELECT COUNT(*) FROM content_critiques');\n        $stats['total_critiques'] = (int) $stmt->fetchColumn();\n\n        return $stats;\n    }\n}\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →