{
"event": "PostToolUse",
"raw_data": {
"session_id": "18ef5bf3-e872-4052-897e-53d6dc45b0b9",
"transcript_path": "\/root\/.claude\/projects\/-var-www\/18ef5bf3-e872-4052-897e-53d6dc45b0b9.jsonl",
"cwd": "\/var\/www",
"permission_mode": "acceptEdits",
"hook_event_name": "PostToolUse",
"tool_name": "Read",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ConfigController.php"
},
"tool_response": {
"type": "text",
"file": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ConfigController.php",
"content": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Config\\DatabaseFactory;\n\nclass ConfigController extends Controller\n{\n private \\PDO $db;\n\n private const TYPES = ['author_profile', 'structure', 'organization', 'contract', 'rule', 'system_prompt'];\n private const TYPE_LABELS = [\n 'author_profile' => 'Autorenprofil',\n 'structure' => 'Struktur',\n 'organization' => 'Organisation',\n 'contract' => 'Contract',\n 'rule' => 'Regel',\n 'system_prompt' => 'System-Prompt',\n ];\n\n public function __construct()\n {\n $this->db = DatabaseFactory::content();\n }\n\n \/**\n * GET \/config\n *\/\n public function index(): void\n {\n $typeFilter = $this->getString('type');\n $statusFilter = $this->getString('status');\n\n $sql = 'SELECT c.*, p.name as parent_name\n FROM content_config c\n LEFT JOIN content_config p ON c.parent_id = p.id\n WHERE 1=1';\n $params = [];\n\n if ($typeFilter !== '' && in_array($typeFilter, self::TYPES, true)) {\n $sql .= ' AND c.type = ?';\n $params[] = $typeFilter;\n }\n\n if ($statusFilter !== '' && in_array($statusFilter, ['draft', 'active', 'deprecated'], true)) {\n $sql .= ' AND c.status = ?';\n $params[] = $statusFilter;\n }\n\n $sql .= ' ORDER BY c.type, c.name';\n\n $stmt = $this->db->prepare($sql);\n $stmt->execute($params);\n $configs = $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n\n $stats = $this->getStatistics();\n\n $this->view('config.index', [\n 'title' => 'Content-Konfiguration',\n 'configs' => $configs,\n 'stats' => $stats,\n 'types' => self::TYPES,\n 'typeLabels' => self::TYPE_LABELS,\n 'currentType' => $typeFilter,\n 'currentStatus' => $statusFilter,\n ]);\n }\n\n \/**\n * GET \/config\/new\n *\/\n public function configNew(): void\n {\n $parents = $this->getParentOptions();\n\n $this->view('config.form', [\n 'title' => 'Neue Konfiguration',\n 'config' => null,\n 'types' => self::TYPES,\n 'typeLabels' => self::TYPE_LABELS,\n 'parents' => $parents,\n 'isEdit' => false,\n ]);\n }\n\n \/**\n * POST \/config\n *\/\n public function store(): void\n {\n $this->requireCsrf();\n\n $type = $_POST['type'] ?? '';\n $name = trim($_POST['name'] ?? '');\n $slug = trim($_POST['slug'] ?? '');\n $description = trim($_POST['description'] ?? '');\n $content = $_POST['content'] ?? '{}';\n $version = trim($_POST['version'] ?? '1.0');\n $status = $_POST['status'] ?? 'draft';\n $parentId = !empty($_POST['parent_id']) ? (int) $_POST['parent_id'] : null;\n\n if (!in_array($type, self::TYPES, true) || $name === '' || $slug === '') {\n $_SESSION['error'] = 'Typ, Name und Slug sind erforderlich.';\n header('Location: \/config\/new');\n exit;\n }\n\n \/\/ JSON validieren\n $decoded = json_decode($content, true);\n if ($decoded === null && $content !== 'null') {\n $_SESSION['error'] = 'Ungültiges JSON-Format.';\n header('Location: \/config\/new');\n exit;\n }\n\n $stmt = $this->db->prepare(\n 'INSERT INTO content_config (type, name, slug, description, content, version, status, parent_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)'\n );\n $stmt->execute([$type, $name, $slug, $description ?: null, $content, $version, $status, $parentId]);\n $id = $this->db->lastInsertId();\n\n $_SESSION['success'] = 'Konfiguration erfolgreich erstellt.';\n header('Location: \/config\/' . $id);\n exit;\n }\n\n \/**\n * GET \/config\/{id}\n *\/\n public function show(string $id): void\n {\n $config = $this->findById((int) $id);\n\n if ($config === null) {\n $this->notFound('Konfiguration nicht gefunden');\n }\n\n $children = $this->getChildren((int) $id);\n $history = $this->getHistory((int) $id);\n\n $this->view('config.show', [\n 'title' => $config['name'],\n 'config' => $config,\n 'children' => $children,\n 'history' => $history,\n 'typeLabels' => self::TYPE_LABELS,\n ]);\n }\n\n \/**\n * GET \/config\/{id}\/edit\n *\/\n public function edit(string $id): void\n {\n $config = $this->findById((int) $id);\n\n if ($config === null) {\n $this->notFound('Konfiguration nicht gefunden');\n }\n\n $parents = $this->getParentOptions((int) $id);\n\n $this->view('config.form', [\n 'title' => 'Bearbeiten: ' . $config['name'],\n 'config' => $config,\n 'types' => self::TYPES,\n 'typeLabels' => self::TYPE_LABELS,\n 'parents' => $parents,\n 'isEdit' => true,\n ]);\n }\n\n \/**\n * POST \/config\/{id}\n *\/\n public function update(string $id): void\n {\n $this->requireCsrf();\n\n $config = $this->findById((int) $id);\n\n if ($config === null) {\n $this->notFound('Konfiguration nicht gefunden');\n }\n\n $name = trim($_POST['name'] ?? '');\n $slug = trim($_POST['slug'] ?? '');\n $description = trim($_POST['description'] ?? '');\n $content = $_POST['content'] ?? '{}';\n $newVersion = trim($_POST['new_version'] ?? '');\n $changeDescription = trim($_POST['change_description'] ?? '');\n $status = $_POST['status'] ?? $config['status'];\n $parentId = !empty($_POST['parent_id']) ? (int) $_POST['parent_id'] : null;\n\n if ($name === '' || $slug === '' || $newVersion === '') {\n $_SESSION['error'] = 'Name, Slug und neue Version sind erforderlich.';\n header('Location: \/config\/' . $id . '\/edit');\n exit;\n }\n\n \/\/ JSON validieren\n $decoded = json_decode($content, true);\n if ($decoded === null && $content !== 'null') {\n $_SESSION['error'] = 'Ungültiges JSON-Format.';\n header('Location: \/config\/' . $id . '\/edit');\n exit;\n }\n\n \/\/ Alte Version in History speichern\n $stmt = $this->db->prepare(\n 'INSERT INTO content_config_history (config_id, content, version, changed_by, change_description)\n VALUES (?, ?, ?, ?, ?)'\n );\n $stmt->execute([\n $id,\n $config['content'],\n $config['version'],\n 'web-ui',\n $changeDescription ?: 'Update auf Version ' . $newVersion,\n ]);\n\n \/\/ Config aktualisieren\n $stmt = $this->db->prepare(\n 'UPDATE content_config\n SET name = ?, slug = ?, description = ?, content = ?, version = ?, status = ?, parent_id = ?\n WHERE id = ?'\n );\n $stmt->execute([$name, $slug, $description ?: null, $content, $newVersion, $status, $parentId, $id]);\n\n $_SESSION['success'] = 'Konfiguration auf Version ' . $newVersion . ' aktualisiert.';\n header('Location: \/config\/' . $id);\n exit;\n }\n\n \/**\n * POST \/config\/{id}\/delete\n *\/\n public function delete(string $id): void\n {\n $this->requireCsrf();\n\n $config = $this->findById((int) $id);\n\n if ($config === null) {\n $this->notFound('Konfiguration nicht gefunden');\n }\n\n \/\/ Prüfen ob Children existieren\n $stmt = $this->db->prepare('SELECT COUNT(*) FROM content_config WHERE parent_id = ?');\n $stmt->execute([$id]);\n if ($stmt->fetchColumn() > 0) {\n $_SESSION['error'] = 'Kann nicht gelöscht werden: Es existieren verknüpfte Einträge.';\n header('Location: \/config\/' . $id);\n exit;\n }\n\n \/\/ History löschen\n $stmt = $this->db->prepare('DELETE FROM content_config_history WHERE config_id = ?');\n $stmt->execute([$id]);\n\n \/\/ Config löschen\n $stmt = $this->db->prepare('DELETE FROM content_config WHERE id = ?');\n $stmt->execute([$id]);\n\n $_SESSION['success'] = 'Konfiguration gelöscht.';\n header('Location: \/config');\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 parent_name\n FROM content_config c\n LEFT JOIN content_config p ON c.parent_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 getStatistics(): array\n {\n $stats = ['total' => 0, 'by_type' => [], 'by_status' => []];\n\n $stmt = $this->db->query('SELECT type, COUNT(*) as cnt FROM content_config GROUP BY type');\n foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {\n $stats['by_type'][$row['type']] = (int) $row['cnt'];\n $stats['total'] += (int) $row['cnt'];\n }\n\n $stmt = $this->db->query('SELECT status, COUNT(*) as cnt FROM content_config GROUP BY status');\n foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {\n $stats['by_status'][$row['status']] = (int) $row['cnt'];\n }\n\n return $stats;\n }\n\n private function getParentOptions(?int $excludeId = null): array\n {\n $sql = 'SELECT id, type, name FROM content_config WHERE type IN (\"contract\", \"organization\") ORDER BY type, name';\n $stmt = $this->db->query($sql);\n $parents = [];\n foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {\n if ($excludeId !== null && (int) $row['id'] === $excludeId) {\n continue;\n }\n $parents[] = $row;\n }\n\n return $parents;\n }\n\n private... [TRUNCATED-672ae65975ec2580]",
"numLines": 339,
"startLine": 1,
"totalLines": 339
}
},
"tool_use_id": "toolu_01C64BUAv4VrGWXNzPEumB2C"
}
}