Protokoll #19372

ID19372
Zeitstempel2025-12-27 00:14:43.216998
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens3,207 (Input: 1,601, Output: 1,606)
Dauer115 ms
Request-Zeit2025-12-27 00:14:43.216998
Response-Zeit2025-12-27 00:14:43.331695

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Infrastructure\/Persistence\/StopwordRepository.php",
        "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Infrastructure\\Persistence;\n\n\/\/ @responsibility: CRUD-Operationen für Stopwords (Entity-Extraction Filter)\n\nuse Domain\\Repository\\StopwordRepositoryInterface;\nuse PDO;\n\nfinal class StopwordRepository implements StopwordRepositoryInterface\n{\n    private PDO $db;\n\n    \/** @var array<string>|null Cached canonical forms *\/\n    private ?array $canonicalCache = null;\n\n    public function __construct(PDO $pdo)\n    {\n        $this->db = $pdo;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function findAll(bool $activeOnly = true, ?string $category = null): array\n    {\n        $sql = 'SELECT * FROM stopwords WHERE 1=1';\n        $params = [];\n\n        if ($activeOnly) {\n            $sql .= ' AND is_active = 1';\n        }\n\n        if ($category !== null) {\n            $sql .= ' AND category = :category';\n            $params['category'] = $category;\n        }\n\n        $sql .= ' ORDER BY word ASC';\n\n        $stmt = $this->db->prepare($sql);\n        $stmt->execute($params);\n\n        return $stmt->fetchAll();\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function find(int $id): ?array\n    {\n        $stmt = $this->db->prepare('SELECT * FROM stopwords WHERE id = :id');\n        $stmt->execute(['id' => $id]);\n        $result = $stmt->fetch();\n\n        return $result === false ? null : $result;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function getCanonicalForms(bool $activeOnly = true): array\n    {\n        if ($this->canonicalCache !== null && $activeOnly) {\n            return $this->canonicalCache;\n        }\n\n        $sql = 'SELECT canonical_form FROM stopwords';\n        if ($activeOnly) {\n            $sql .= ' WHERE is_active = 1';\n        }\n\n        $stmt = $this->db->query($sql);\n        $forms = $stmt->fetchAll(PDO::FETCH_COLUMN);\n\n        if ($activeOnly) {\n            $this->canonicalCache = $forms;\n        }\n\n        return $forms;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function isStopword(string $word): bool\n    {\n        $canonical = $this->normalize($word);\n        $forms = $this->getCanonicalForms();\n\n        return in_array($canonical, $forms, true);\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function create(array $data): int\n    {\n        $canonical = $this->normalize($data['word'] ?? '');\n\n        $stmt = $this->db->prepare(\n            'INSERT INTO stopwords (word, canonical_form, category, reason, is_active)\n             VALUES (:word, :canonical, :category, :reason, :active)'\n        );\n\n        $stmt->execute([\n            'word' => $data['word'],\n            'canonical' => $canonical,\n            'category' => $data['category'] ?? 'generic',\n            'reason' => $data['reason'] ?? null,\n            'active' => $data['is_active'] ?? 1,\n        ]);\n\n        $this->canonicalCache = null;\n\n        return (int) $this->db->lastInsertId();\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function update(int $id, array $data): bool\n    {\n        $sets = [];\n        $params = ['id' => $id];\n\n        if (isset($data['word'])) {\n            $sets[] = 'word = :word';\n            $sets[] = 'canonical_form = :canonical';\n            $params['word'] = $data['word'];\n            $params['canonical'] = $this->normalize($data['word']);\n        }\n\n        if (isset($data['category'])) {\n            $sets[] = 'category = :category';\n            $params['category'] = $data['category'];\n        }\n\n        if (array_key_exists('reason', $data)) {\n            $sets[] = 'reason = :reason';\n            $params['reason'] = $data['reason'];\n        }\n\n        if (isset($data['is_active'])) {\n            $sets[] = 'is_active = :active';\n            $params['active'] = $data['is_active'];\n        }\n\n        if ($sets === []) {\n            return false;\n        }\n\n        $sql = 'UPDATE stopwords SET ' . implode(', ', $sets) . ' WHERE id = :id';\n        $stmt = $this->db->prepare($sql);\n        $result = $stmt->execute($params);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function delete(int $id): bool\n    {\n        $stmt = $this->db->prepare('DELETE FROM stopwords WHERE id = :id');\n        $result = $stmt->execute(['id' => $id]);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function toggleActive(int $id): bool\n    {\n        $stmt = $this->db->prepare(\n            'UPDATE stopwords SET is_active = NOT is_active WHERE id = :id'\n        );\n        $result = $stmt->execute(['id' => $id]);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function getStats(): array\n    {\n        $stmt = $this->db->query(\n            'SELECT category, COUNT(*) as count, SUM(is_active) as active\n             FROM stopwords GROUP BY category'\n        );\n\n        $stats = ['total' => 0, 'active' => 0, 'by_category' => []];\n\n        foreach ($stmt->fetchAll() as $row) {\n            $stats['by_category'][$row['category']] = [\n                'count' => (int) $row['count'],\n                'active' => (int) $row['active'],\n            ];\n            $stats['total'] += (int) $row['count'];\n            $stats['active'] += (int) $row['active'];\n        }\n\n        return $stats;\n    }\n\n    \/**\n     * Normalize word to canonical form.\n     *\/\n    private function normalize(string $word): string\n    {\n        $result = mb_strtolower(trim($word));\n\n        \/\/ German umlauts\n        $replacements = [\n            'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',\n        ];\n        $result = str_replace(array_keys($replacements), array_values($replacements), $result);\n\n        \/\/ Remove special chars, keep only alphanumeric and underscore\n        $result = preg_replace('\/[^a-z0-9_]\/', '', $result);\n\n        return $result ?? '';\n    }\n}\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Infrastructure\/Persistence\/StopwordRepository.php",
        "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Infrastructure\\Persistence;\n\n\/\/ @responsibility: CRUD-Operationen für Stopwords (Entity-Extraction Filter)\n\nuse Domain\\Repository\\StopwordRepositoryInterface;\nuse PDO;\n\nfinal class StopwordRepository implements StopwordRepositoryInterface\n{\n    private PDO $db;\n\n    \/** @var array<string>|null Cached canonical forms *\/\n    private ?array $canonicalCache = null;\n\n    public function __construct(PDO $pdo)\n    {\n        $this->db = $pdo;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function findAll(bool $activeOnly = true, ?string $category = null): array\n    {\n        $sql = 'SELECT * FROM stopwords WHERE 1=1';\n        $params = [];\n\n        if ($activeOnly) {\n            $sql .= ' AND is_active = 1';\n        }\n\n        if ($category !== null) {\n            $sql .= ' AND category = :category';\n            $params['category'] = $category;\n        }\n\n        $sql .= ' ORDER BY word ASC';\n\n        $stmt = $this->db->prepare($sql);\n        $stmt->execute($params);\n\n        return $stmt->fetchAll();\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function find(int $id): ?array\n    {\n        $stmt = $this->db->prepare('SELECT * FROM stopwords WHERE id = :id');\n        $stmt->execute(['id' => $id]);\n        $result = $stmt->fetch();\n\n        return $result === false ? null : $result;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function getCanonicalForms(bool $activeOnly = true): array\n    {\n        if ($this->canonicalCache !== null && $activeOnly) {\n            return $this->canonicalCache;\n        }\n\n        $sql = 'SELECT canonical_form FROM stopwords';\n        if ($activeOnly) {\n            $sql .= ' WHERE is_active = 1';\n        }\n\n        $stmt = $this->db->query($sql);\n        $forms = $stmt->fetchAll(PDO::FETCH_COLUMN);\n\n        if ($activeOnly) {\n            $this->canonicalCache = $forms;\n        }\n\n        return $forms;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function isStopword(string $word): bool\n    {\n        $canonical = $this->normalize($word);\n        $forms = $this->getCanonicalForms();\n\n        return in_array($canonical, $forms, true);\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function create(array $data): int\n    {\n        $canonical = $this->normalize($data['word'] ?? '');\n\n        $stmt = $this->db->prepare(\n            'INSERT INTO stopwords (word, canonical_form, category, reason, is_active)\n             VALUES (:word, :canonical, :category, :reason, :active)'\n        );\n\n        $stmt->execute([\n            'word' => $data['word'],\n            'canonical' => $canonical,\n            'category' => $data['category'] ?? 'generic',\n            'reason' => $data['reason'] ?? null,\n            'active' => $data['is_active'] ?? 1,\n        ]);\n\n        $this->canonicalCache = null;\n\n        return (int) $this->db->lastInsertId();\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function update(int $id, array $data): bool\n    {\n        $sets = [];\n        $params = ['id' => $id];\n\n        if (isset($data['word'])) {\n            $sets[] = 'word = :word';\n            $sets[] = 'canonical_form = :canonical';\n            $params['word'] = $data['word'];\n            $params['canonical'] = $this->normalize($data['word']);\n        }\n\n        if (isset($data['category'])) {\n            $sets[] = 'category = :category';\n            $params['category'] = $data['category'];\n        }\n\n        if (array_key_exists('reason', $data)) {\n            $sets[] = 'reason = :reason';\n            $params['reason'] = $data['reason'];\n        }\n\n        if (isset($data['is_active'])) {\n            $sets[] = 'is_active = :active';\n            $params['active'] = $data['is_active'];\n        }\n\n        if ($sets === []) {\n            return false;\n        }\n\n        $sql = 'UPDATE stopwords SET ' . implode(', ', $sets) . ' WHERE id = :id';\n        $stmt = $this->db->prepare($sql);\n        $result = $stmt->execute($params);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function delete(int $id): bool\n    {\n        $stmt = $this->db->prepare('DELETE FROM stopwords WHERE id = :id');\n        $result = $stmt->execute(['id' => $id]);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function toggleActive(int $id): bool\n    {\n        $stmt = $this->db->prepare(\n            'UPDATE stopwords SET is_active = NOT is_active WHERE id = :id'\n        );\n        $result = $stmt->execute(['id' => $id]);\n\n        $this->canonicalCache = null;\n\n        return $result && $stmt->rowCount() > 0;\n    }\n\n    \/**\n     * {@inheritDoc}\n     *\/\n    public function getStats(): array\n    {\n        $stmt = $this->db->query(\n            'SELECT category, COUNT(*) as count, SUM(is_active) as active\n             FROM stopwords GROUP BY category'\n        );\n\n        $stats = ['total' => 0, 'active' => 0, 'by_category' => []];\n\n        foreach ($stmt->fetchAll() as $row) {\n            $stats['by_category'][$row['category']] = [\n                'count' => (int) $row['count'],\n                'active' => (int) $row['active'],\n            ];\n            $stats['total'] += (int) $row['count'];\n            $stats['active'] += (int) $row['active'];\n        }\n\n        return $stats;\n    }\n\n    \/**\n     * Normalize word to canonical form.\n     *\/\n    private function normalize(string $word): string\n    {\n        $result = mb_strtolower(trim($word));\n\n        \/\/ German umlauts\n        $replacements = [\n            'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',\n        ];\n        $result = str_replace(array_keys($replacements), array_values($replacements), $result);\n\n        \/\/ Remove special chars, keep only alphanumeric and underscore\n        $result = preg_replace('\/[^a-z0-9_]\/', '', $result);\n\n        return $result ?? '';\n    }\n}\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →