Protokoll #4567

ID4567
Zeitstempel2025-12-22 10:18:32.240723
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens14,589 (Input: 4,398, Output: 10,191)
Dauer89 ms
Request-Zeit2025-12-22 10:18:32.240723
Response-Zeit2025-12-22 10:18:32.330118

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ConfigController.php",
        "old_string": "<?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-89fcc95c0bb6b31d]",
        "new_string": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Persistence\\ContentConfigRepository;\n\nclass ConfigController extends Controller\n{\n    private ContentConfigRepository $configRepo;\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(?ContentConfigRepository $configRepo = null)\n    {\n        $this->configRepo = $configRepo ?? new ContentConfigRepository();\n    }\n\n    public function index(): void\n    {\n        $typeFilter = $this->getString('type');\n        $statusFilter = $this->getString('status');\n\n        $validType = in_array($typeFilter, self::TYPES, true) ? $typeFilter : null;\n        $validStatus = in_array($statusFilter, ['draft', 'active', 'deprecated'], true) ? $statusFilter : null;\n\n        $this->view('config.index', [\n            'title' => 'Content-Konfiguration',\n            'configs' => $this->configRepo->findAll($validType, $validStatus),\n            'stats' => $this->configRepo->getStatistics(),\n            'types' => self::TYPES,\n            'typeLabels' => self::TYPE_LABELS,\n            'currentType' => $typeFilter,\n            'currentStatus' => $statusFilter,\n        ]);\n    }\n\n    public function configNew(): void\n    {\n        $this->view('config.form', [\n            'title' => 'Neue Konfiguration',\n            'config' => null,\n            'types' => self::TYPES,\n            'typeLabels' => self::TYPE_LABELS,\n            'parents' => $this->configRepo->getParentOptions(),\n            'isEdit' => false,\n        ]);\n    }\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        $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        $id = $this->configRepo->create(\n            $type,\n            $name,\n            $slug,\n            $description !== '' ? $description : null,\n            $content,\n            $version,\n            $status,\n            $parentId\n        );\n\n        $_SESSION['success'] = 'Konfiguration erfolgreich erstellt.';\n        header('Location: \/config\/' . $id);\n        exit;\n    }\n\n    public function show(string $id): void\n    {\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\n\n        $this->view('config.show', [\n            'title' => $config['name'],\n            'config' => $config,\n            'children' => $this->configRepo->getChildren((int) $id),\n            'history' => $this->configRepo->getHistory((int) $id),\n            'typeLabels' => self::TYPE_LABELS,\n        ]);\n    }\n\n    public function edit(string $id): void\n    {\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\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' => $this->configRepo->getParentOptions((int) $id),\n            'isEdit' => true,\n        ]);\n    }\n\n    public function update(string $id): void\n    {\n        $this->requireCsrf();\n\n        $config = $this->configRepo->findById((int) $id);\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        $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        $this->configRepo->saveHistory(\n            (int) $id,\n            $config['content'],\n            $config['version'],\n            'web-ui',\n            $changeDescription !== '' ? $changeDescription : 'Update auf Version ' . $newVersion\n        );\n\n        $this->configRepo->update(\n            (int) $id,\n            $name,\n            $slug,\n            $description !== '' ? $description : null,\n            $content,\n            $newVersion,\n            $status,\n            $parentId\n        );\n\n        $_SESSION['success'] = 'Konfiguration auf Version ' . $newVersion . ' aktualisiert.';\n        header('Location: \/config\/' . $id);\n        exit;\n    }\n\n    public function delete(string $id): void\n    {\n        $this->requireCsrf();\n\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\n\n        if ($this->configRepo->countChildren((int) $id) > 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        $this->configRepo->deleteHistory((int) $id);\n        $this->configRepo->delete((int) $id);\n\n        $_SESSION['success'] = 'Konfiguration gelöscht.';\n        header('Location: \/config');\n        exit;\n    }\n}"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ConfigController.php",
        "oldString": "<?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-89fcc95c0bb6b31d]",
        "newString": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\Persistence\\ContentConfigRepository;\n\nclass ConfigController extends Controller\n{\n    private ContentConfigRepository $configRepo;\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(?ContentConfigRepository $configRepo = null)\n    {\n        $this->configRepo = $configRepo ?? new ContentConfigRepository();\n    }\n\n    public function index(): void\n    {\n        $typeFilter = $this->getString('type');\n        $statusFilter = $this->getString('status');\n\n        $validType = in_array($typeFilter, self::TYPES, true) ? $typeFilter : null;\n        $validStatus = in_array($statusFilter, ['draft', 'active', 'deprecated'], true) ? $statusFilter : null;\n\n        $this->view('config.index', [\n            'title' => 'Content-Konfiguration',\n            'configs' => $this->configRepo->findAll($validType, $validStatus),\n            'stats' => $this->configRepo->getStatistics(),\n            'types' => self::TYPES,\n            'typeLabels' => self::TYPE_LABELS,\n            'currentType' => $typeFilter,\n            'currentStatus' => $statusFilter,\n        ]);\n    }\n\n    public function configNew(): void\n    {\n        $this->view('config.form', [\n            'title' => 'Neue Konfiguration',\n            'config' => null,\n            'types' => self::TYPES,\n            'typeLabels' => self::TYPE_LABELS,\n            'parents' => $this->configRepo->getParentOptions(),\n            'isEdit' => false,\n        ]);\n    }\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        $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        $id = $this->configRepo->create(\n            $type,\n            $name,\n            $slug,\n            $description !== '' ? $description : null,\n            $content,\n            $version,\n            $status,\n            $parentId\n        );\n\n        $_SESSION['success'] = 'Konfiguration erfolgreich erstellt.';\n        header('Location: \/config\/' . $id);\n        exit;\n    }\n\n    public function show(string $id): void\n    {\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\n\n        $this->view('config.show', [\n            'title' => $config['name'],\n            'config' => $config,\n            'children' => $this->configRepo->getChildren((int) $id),\n            'history' => $this->configRepo->getHistory((int) $id),\n            'typeLabels' => self::TYPE_LABELS,\n        ]);\n    }\n\n    public function edit(string $id): void\n    {\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\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' => $this->configRepo->getParentOptions((int) $id),\n            'isEdit' => true,\n        ]);\n    }\n\n    public function update(string $id): void\n    {\n        $this->requireCsrf();\n\n        $config = $this->configRepo->findById((int) $id);\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        $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        $this->configRepo->saveHistory(\n            (int) $id,\n            $config['content'],\n            $config['version'],\n            'web-ui',\n            $changeDescription !== '' ? $changeDescription : 'Update auf Version ' . $newVersion\n        );\n\n        $this->configRepo->update(\n            (int) $id,\n            $name,\n            $slug,\n            $description !== '' ? $description : null,\n            $content,\n            $newVersion,\n            $status,\n            $parentId\n        );\n\n        $_SESSION['success'] = 'Konfiguration auf Version ' . $newVersion . ' aktualisiert.';\n        header('Location: \/config\/' . $id);\n        exit;\n    }\n\n    public function delete(string $id): void\n    {\n        $this->requireCsrf();\n\n        $config = $this->configRepo->findById((int) $id);\n        if ($config === null) {\n            $this->notFound('Konfiguration nicht gefunden');\n        }\n\n        if ($this->configRepo->countChildren((int) $id) > 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        $this->configRepo->deleteHistory((int) $id);\n        $this->configRepo->delete((int) $id);\n\n        $_SESSION['success'] = 'Konfiguration gelöscht.';\n        header('Location: \/config');\n        exit;\n    }\n}",
        "originalFile": "<?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]",
        "structuredPatch": [
            {
                "oldStart": 3,
                "oldLines": 11,
                "newStart": 3,
                "newLines": 11,
                "lines": [
                    " namespace Controller;",
                    " ",
                    " use Framework\\Controller;",
                    "-use Infrastructure\\Config\\DatabaseFactory;",
                    "+use Infrastructure\\Persistence\\ContentConfigRepository;",
                    " ",
                    " class ConfigController extends Controller",
                    " {",
                    "-    private \\PDO $db;",
                    "+    private ContentConfigRepository $configRepo;",
                    " ",
                    "     private const TYPES = ['author_profile', 'structure', 'organization', 'contract', 'rule', 'system_prompt'];",
                    "     private const TYPE_LABELS = ["
                ]
            },
            {
                "oldStart": 19,
                "oldLines": 47,
                "newStart": 19,
                "newLines": 23,
                "lines": [
                    "         'system_prompt' => 'System-Prompt',",
                    "     ];",
                    " ",
                    "-    public function __construct()",
                    "+    public function __construct(?ContentConfigRepository $configRepo = null)",
                    "     {",
                    "-        $this->db = DatabaseFactory::content();",
                    "+        $this->configRepo = $configRepo ?? new ContentConfigRepository();",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/config",
                    "-     *\/",
                    "     public function index(): void",
                    "     {",
                    "         $typeFilter = $this->getString('type');",
                    "         $statusFilter = $this->getString('status');",
                    " ",
                    "-        $sql = 'SELECT c.*, p.name as parent_name",
                    "-                FROM content_config c",
                    "-                LEFT JOIN content_config p ON c.parent_id = p.id",
                    "-                WHERE 1=1';",
                    "-        $params = [];",
                    "+        $validType = in_array($typeFilter, self::TYPES, true) ? $typeFilter : null;",
                    "+        $validStatus = in_array($statusFilter, ['draft', 'active', 'deprecated'], true) ? $statusFilter : null;",
                    " ",
                    "-        if ($typeFilter !== '' && in_array($typeFilter, self::TYPES, true)) {",
                    "-            $sql .= ' AND c.type = ?';",
                    "-            $params[] = $typeFilter;",
                    "-        }",
                    "-",
                    "-        if ($statusFilter !== '' && in_array($statusFilter, ['draft', 'active', 'deprecated'], true)) {",
                    "-            $sql .= ' AND c.status = ?';",
                    "-            $params[] = $statusFilter;",
                    "-        }",
                    "-",
                    "-        $sql .= ' ORDER BY c.type, c.name';",
                    "-",
                    "-        $stmt = $this->db->prepare($sql);",
                    "-        $stmt->execute($params);",
                    "-        $configs = $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-",
                    "-        $stats = $this->getStatistics();",
                    "-",
                    "         $this->view('config.index', [",
                    "             'title' => 'Content-Konfiguration',",
                    "-            'configs' => $configs,",
                    "-            'stats' => $stats,",
                    "+            'configs' => $this->configRepo->findAll($validType, $validStatus),",
                    "+            'stats' => $this->configRepo->getStatistics(),",
                    "             'types' => self::TYPES,",
                    "             'typeLabels' => self::TYPE_LABELS,",
                    "             'currentType' => $typeFilter,"
                ]
            },
            {
                "oldStart": 67,
                "oldLines": 26,
                "newStart": 43,
                "newLines": 18,
                "lines": [
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/config\/new",
                    "-     *\/",
                    "     public function configNew(): void",
                    "     {",
                    "-        $parents = $this->getParentOptions();",
                    "-",
                    "         $this->view('config.form', [",
                    "             'title' => 'Neue Konfiguration',",
                    "             'config' => null,",
                    "             'types' => self::TYPES,",
                    "             'typeLabels' => self::TYPE_LABELS,",
                    "-            'parents' => $parents,",
                    "+            'parents' => $this->configRepo->getParentOptions(),",
                    "             'isEdit' => false,",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/config",
                    "-     *\/",
                    "     public function store(): void",
                    "     {",
                    "         $this->requireCsrf();"
                ]
            },
            {
                "oldStart": 106,
                "oldLines": 7,
                "newStart": 74,
                "newLines": 6,
                "lines": [
                    "             exit;",
                    "         }",
                    " ",
                    "-        \/\/ JSON validieren",
                    "         $decoded = json_decode($content, true);",
                    "         if ($decoded === null && $content !== 'null') {",
                    "             $_SESSION['error'] = 'Ungültiges JSON-Format.';"
                ]
            },
            {
                "oldStart": 114,
                "oldLines": 73,
                "newStart": 81,
                "newLines": 60,
                "lines": [
                    "             exit;",
                    "         }",
                    " ",
                    "-        $stmt = $this->db->prepare(",
                    "-            'INSERT INTO content_config (type, name, slug, description, content, version, status, parent_id)",
                    "-             VALUES (?, ?, ?, ?, ?, ?, ?, ?)'",
                    "+        $id = $this->configRepo->create(",
                    "+            $type,",
                    "+            $name,",
                    "+            $slug,",
                    "+            $description !== '' ? $description : null,",
                    "+            $content,",
                    "+            $version,",
                    "+            $status,",
                    "+            $parentId",
                    "         );",
                    "-        $stmt->execute([$type, $name, $slug, $description ?: null, $content, $version, $status, $parentId]);",
                    "-        $id = $this->db->lastInsertId();",
                    " ",
                    "         $_SESSION['success'] = 'Konfiguration erfolgreich erstellt.';",
                    "         header('Location: \/config\/' . $id);",
                    "         exit;",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/config\/{id}",
                    "-     *\/",
                    "     public function show(string $id): void",
                    "     {",
                    "-        $config = $this->findById((int) $id);",
                    "-",
                    "+        $config = $this->configRepo->findById((int) $id);",
                    "         if ($config === null) {",
                    "             $this->notFound('Konfiguration nicht gefunden');",
                    "         }",
                    " ",
                    "-        $children = $this->getChildren((int) $id);",
                    "-        $history = $this->getHistory((int) $id);",
                    "-",
                    "         $this->view('config.show', [",
                    "             'title' => $config['name'],",
                    "             'config' => $config,",
                    "-            'children' => $children,",
                    "-            'history' => $history,",
                    "+            'children' => $this->configRepo->getChildren((int) $id),",
                    "+            'history' => $this->configRepo->getHistory((int) $id),",
                    "             'typeLabels' => self::TYPE_LABELS,",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/config\/{id}\/edit",
                    "-     *\/",
                    "     public function edit(string $id): void",
                    "     {",
                    "-        $config = $this->findById((int) $id);",
                    "-",
                    "+        $config = $this->configRepo->findById((int) $id);",
                    "         if ($config === null) {",
                    "             $this->notFound('Konfiguration nicht gefunden');",
                    "         }",
                    " ",
                    "-        $parents = $this->getParentOptions((int) $id);",
                    "-",
                    "         $this->view('config.form', [",
                    "             'title' => 'Bearbeiten: ' . $config['name'],",
                    "             'config' => $config,",
                    "             'types' => self::TYPES,",
                    "             'typeLabels' => self::TYPE_LABELS,",
                    "-            'parents' => $parents,",
                    "+            'parents' => $this->configRepo->getParentOptions((int) $id),",
                    "             'isEdit' => true,",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/config\/{id}",
                    "-     *\/",
                    "     public function update(string $id): void",
                    "     {",
                    "         $this->requireCsrf();",
                    " ",
                    "-        $config = $this->findById((int) $id);",
                    "-",
                    "+        $config = $this->configRepo->findById((int) $id);",
                    "         if ($config === null) {",
                    "             $this->notFound('Konfiguration nicht gefunden');",
                    "         }"
                ]
            },
            {
                "oldStart": 200,
                "oldLines": 7,
                "newStart": 154,
                "newLines": 6,
                "lines": [
                    "             exit;",
                    "         }",
                    " ",
                    "-        \/\/ JSON validieren",
                    "         $decoded = json_decode($content, true);",
                    "         if ($decoded === null && $content !== 'null') {",
                    "             $_SESSION['error'] = 'Ungültiges JSON-Format.';"
                ]
            },
            {
                "oldStart": 208,
                "oldLines": 131,
                "newStart": 161,
                "newLines": 50,
                "lines": [
                    "             exit;",
                    "         }",
                    " ",
                    "-        \/\/ Alte Version in History speichern",
                    "-        $stmt = $this->db->prepare(",
                    "-            'INSERT INTO content_config_history (config_id, content, version, changed_by, change_description)",
                    "-             VALUES (?, ?, ?, ?, ?)'",
                    "-        );",
                    "-        $stmt->execute([",
                    "-            $id,",
                    "+        $this->configRepo->saveHistory(",
                    "+            (int) $id,",
                    "             $config['content'],",
                    "             $config['version'],",
                    "             'web-ui',",
                    "-            $changeDescription ?: 'Update auf Version ' . $newVersion,",
                    "-        ]);",
                    "+            $changeDescription !== '' ? $changeDescription : 'Update auf Version ' . $newVersion",
                    "+        );",
                    " ",
                    "-        \/\/ Config aktualisieren",
                    "-        $stmt = $this->db->prepare(",
                    "-            'UPDATE content_config",
                    "-             SET name = ?, slug = ?, description = ?, content = ?, version = ?, status = ?, parent_id = ?",
                    "-             WHERE id = ?'",
                    "+        $this->configRepo->update(",
                    "+            (int) $id,",
                    "+            $name,",
                    "+            $slug,",
                    "+            $description !== '' ? $description : null,",
                    "+            $content,",
                    "+            $newVersion,",
                    "+            $status,",
                    "+            $parentId",
                    "         );",
                    "-        $stmt->execute([$name, $slug, $description ?: null, $content, $newVersion, $status, $parentId, $id]);",
                    " ",
                    "         $_SESSION['success'] = 'Konfiguration auf Version ' . $newVersion . ' aktualisiert.';",
                    "         header('Location: \/config\/' . $id);",
                    "         exit;",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/config\/{id}\/delete",
                    "-     *\/",
                    "     public function delete(string $id): void",
                    "     {",
                    "         $this->requireCsrf();",
                    " ",
                    "-        $config = $this->findById((int) $id);",
                    "-",
                    "+        $config = $this->configRepo->findById((int) $id);",
                    "         if ($config === null) {",
                    "             $this->notFound('Konfiguration nicht gefunden');",
                    "         }",
                    " ",
                    "-        \/\/ Prüfen ob Children existieren",
                    "-        $stmt = $this->db->prepare('SELECT COUNT(*) FROM content_config WHERE parent_id = ?');",
                    "-        $stmt->execute([$id]);",
                    "-        if ($stmt->fetchColumn() > 0) {",
                    "+        if ($this->configRepo->countChildren((int) $id) > 0) {",
                    "             $_SESSION['error'] = 'Kann nicht gelöscht werden: Es existieren verknüpfte Einträge.';",
                    "             header('Location: \/config\/' . $id);",
                    "             exit;",
                    "         }",
                    " ",
                    "-        \/\/ History löschen",
                    "-        $stmt = $this->db->prepare('DELETE FROM content_config_history WHERE config_id = ?');",
                    "-        $stmt->execute([$id]);",
                    "+        $this->configRepo->deleteHistory((int) $id);",
                    "+        $this->configRepo->delete((int) $id);",
                    " ",
                    "-        \/\/ Config löschen",
                    "-        $stmt = $this->db->prepare('DELETE FROM content_config WHERE id = ?');",
                    "-        $stmt->execute([$id]);",
                    "-",
                    "         $_SESSION['success'] = 'Konfiguration gelöscht.';",
                    "         header('Location: \/config');",
                    "         exit;",
                    "     }",
                    "-",
                    "-    \/\/ ========== Private Helpers ==========",
                    "-",
                    "-    private function findById(int $id): ?array",
                    "-    {",
                    "-        $stmt = $this->db->prepare(",
                    "-            'SELECT c.*, p.name as parent_name",
                    "-             FROM content_config c",
                    "-             LEFT JOIN content_config p ON c.parent_id = p.id",
                    "-             WHERE c.id = ?'",
                    "-        );",
                    "-        $stmt->execute([$id]);",
                    "-        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);",
                    "-",
                    "-        return $result !== false ? $result : null;",
                    "-    }",
                    "-",
                    "-    private function getStatistics(): array",
                    "-    {",
                    "-        $stats = ['total' => 0, 'by_type' => [], 'by_status' => []];",
                    "-",
                    "-        $stmt = $this->db->query('SELECT type, COUNT(*) as cnt FROM content_config GROUP BY type');",
                    "-        foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {",
                    "-            $stats['by_type'][$row['type']] = (int) $row['cnt'];",
                    "-            $stats['total'] += (int) $row['cnt'];",
                    "-        }",
                    "-",
                    "-        $stmt = $this->db->query('SELECT status, COUNT(*) as cnt FROM content_config GROUP BY status');",
                    "-        foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {",
                    "-            $stats['by_status'][$row['status']] = (int) $row['cnt'];",
                    "-        }",
                    "-",
                    "-        return $stats;",
                    "-    }",
                    "-",
                    "-    private function getParentOptions(?int $excludeId = null): array",
                    "-    {",
                    "-        $sql = 'SELECT id, type, name FROM content_config WHERE type IN (\"contract\", \"organization\") ORDER BY type, name';",
                    "-        $stmt = $this->db->query($sql);",
                    "-        $parents = [];",
                    "-        foreach ($stmt->fetchAll(\\PDO::FETCH_ASSOC) as $row) {",
                    "-            if ($excludeId !== null && (int) $row['id'] === $excludeId) {",
                    "-                continue;",
                    "-            }",
                    "-            $parents[] = $row;",
                    "-        }",
                    "-",
                    "-        return $parents;",
                    "-    }",
                    "-",
                    "-    private function getChildren(int $parentId): array",
                    "-    {",
                    "-        $stmt = $this->db->prepare('SELECT * FROM content_config WHERE parent_id = ? ORDER BY name');",
                    "-        $stmt->execute([$parentId]);",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    "-",
                    "-    private function getHistory(int $configId): array",
                    "-    {",
                    "-        $stmt = $this->db->prepare(",
                    "-            'SELECT * FROM content_config_history WHERE config_id = ? ORDER BY created_at DESC LIMIT 10'",
                    "-        );",
                    "-        $stmt->execute([$configId]);",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    " }"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →