DocsController.php
- Pfad:
src/Controller/Api/DocsController.php - Namespace: Controller\Api
- Zeilen: 340 | Größe: 10,287 Bytes
- Geändert: 2025-12-28 23:26:10 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 96
- Dependencies: 100 (25%)
- LOC: 80 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 100 (10%)
Keine Issues gefunden.
Dependencies 9
- extends Framework\Controller
- constructor Domain\Repository\DokumentationRepositoryInterface
- constructor Infrastructure\Docs\ChunkSearchService
- constructor UseCases\Docs\DocumentationChatUseCase
- use Domain\Constants
- use Domain\Repository\DokumentationRepositoryInterface
- use Framework\Controller
- use Infrastructure\Docs\ChunkSearchService
- use UseCases\Docs\DocumentationChatUseCase
Klassen 1
-
DocsControllerclass Zeile 15
Funktionen 10
-
__construct()public Zeile 21 -
index()public Zeile 35 -
show()public Zeile 77 -
showByPath()public Zeile 115 -
store()public Zeile 141 -
update()public Zeile 182 -
destroy()public Zeile 219 -
search()public Zeile 257 -
hierarchy()public Zeile 295 -
chat()public Zeile 314
Versionen 20
-
v20
2025-12-28 23:26 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v19
2025-12-28 23:26 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v18
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v17
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v16
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v15
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v14
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v13
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v12
2025-12-28 23:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v11
2025-12-28 01:01 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v10
2025-12-28 01:00 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v9
2025-12-25 13:01 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v8
2025-12-25 13:01 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v7
2025-12-25 12:52 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v6
2025-12-23 07:53 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v5
2025-12-23 04:43 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v4
2025-12-23 04:27 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v3
2025-12-23 04:26 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v2
2025-12-23 04:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v1
2025-12-23 03:41 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation
Code
<?php
declare(strict_types=1);
namespace Controller\Api;
// @responsibility: REST-API für Dokumentations-CRUD und Semantic Search
use Domain\Constants;
use Domain\Repository\DokumentationRepositoryInterface;
use Framework\Controller;
use Infrastructure\Docs\ChunkSearchService;
use UseCases\Docs\DocumentationChatUseCase;
class DocsController extends Controller
{
private DokumentationRepositoryInterface $repository;
private ChunkSearchService $searchService;
private DocumentationChatUseCase $chatUseCase;
public function __construct(
DokumentationRepositoryInterface $repository,
ChunkSearchService $searchService,
DocumentationChatUseCase $chatUseCase
) {
$this->repository = $repository;
$this->searchService = $searchService;
$this->chatUseCase = $chatUseCase;
}
/**
* GET /api/v1/docs
* Liste aller Dokumente mit optionalen Filtern.
*/
public function index(): void
{
try {
$status = $this->getString('status');
$parentId = $this->getInt('parent_id');
$search = $this->getString('search');
$limit = $this->getLimit(Constants::DEFAULT_LIMIT, 50);
$offset = $this->getInt('offset');
$docs = $this->repository->findAll(
status: $status ?: null,
parentId: $parentId > 0 ? $parentId : null,
search: $search ?: null,
limit: $limit,
offset: $offset
);
$total = $this->repository->count(
status: $status ?: null,
parentId: $parentId > 0 ? $parentId : null,
search: $search ?: null
);
$this->json([
'success' => true,
'data' => $docs,
'meta' => [
'total' => $total,
'limit' => $limit,
'offset' => $offset,
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.index] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/docs/{id}
* Einzelnes Dokument mit optionalen Kindern und Breadcrumb.
*/
public function show(string $id): void
{
try {
$includeChildren = $this->getString('include_children') === '1';
$includeBreadcrumb = $this->getString('include_breadcrumb') === '1';
$doc = $this->repository->findById((int) $id);
if ($doc === null) {
$this->json(['success' => false, 'error' => 'Dokument nicht gefunden'], 404);
return;
}
$response = [
'success' => true,
'data' => $doc,
];
if ($includeChildren) {
$response['children'] = $this->repository->findChildren((int) $id);
}
if ($includeBreadcrumb) {
$response['breadcrumb'] = $this->repository->getBreadcrumb((int) $id);
}
$this->json($response);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.show] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/docs/path/{path}
* Dokument nach Pfad.
*/
public function showByPath(string $path): void
{
try {
$fullPath = '/' . ltrim($path, '/');
$doc = $this->repository->findByPath($fullPath);
if ($doc === null) {
$this->json(['success' => false, 'error' => 'Dokument nicht gefunden'], 404);
return;
}
$this->json([
'success' => true,
'data' => $doc,
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.showByPath] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* POST /api/v1/docs
* Neues Dokument erstellen.
*/
public function store(): void
{
try {
$input = $this->getJsonInput();
$required = ['title', 'slug'];
foreach ($required as $field) {
if (empty($input[$field])) {
$this->json(['success' => false, 'error' => "Feld '$field' ist erforderlich"], 400);
return;
}
}
$docId = $this->repository->create([
'title' => trim($input['title']),
'slug' => trim($input['slug']),
'content' => $input['content'] ?? '',
'description' => $input['description'] ?? null,
'parent_id' => $input['parent_id'] ?? null,
'status' => $input['status'] ?? 'draft',
'sort_order' => $input['sort_order'] ?? 0,
]);
$doc = $this->repository->findById($docId);
$this->json([
'success' => true,
'data' => $doc,
'message' => 'Dokument erstellt',
], 201);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.store] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* PUT /api/v1/docs/{id}
* Dokument aktualisieren.
*/
public function update(string $id): void
{
try {
$doc = $this->repository->findById((int) $id);
if ($doc === null) {
$this->json(['success' => false, 'error' => 'Dokument nicht gefunden'], 404);
return;
}
$input = $this->getJsonInput();
$this->repository->update((int) $id, [
'title' => $input['title'] ?? $doc['title'],
'content' => $input['content'] ?? $doc['content'],
'description' => $input['description'] ?? $doc['description'],
'status' => $input['status'] ?? $doc['status'],
]);
$updated = $this->repository->findById((int) $id);
$this->json([
'success' => true,
'data' => $updated,
'message' => 'Dokument aktualisiert',
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.update] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* DELETE /api/v1/docs/{id}
* Dokument löschen.
*/
public function destroy(string $id): void
{
try {
$doc = $this->repository->findById((int) $id);
if ($doc === null) {
$this->json(['success' => false, 'error' => 'Dokument nicht gefunden'], 404);
return;
}
// Check for children
$children = $this->repository->findChildren((int) $id);
if (!empty($children)) {
$this->json([
'success' => false,
'error' => 'Dokument hat Unterdokumente. Lösche diese zuerst.',
], 400);
return;
}
$this->repository->delete((int) $id);
$this->json([
'success' => true,
'message' => 'Dokument gelöscht',
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.destroy] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/docs/search
* Semantic search über Dokumentation.
*/
public function search(): void
{
try {
$query = $this->getString('q');
$limit = $this->getInt('limit', 5);
$category = $this->getString('category');
if ($query === '') {
$this->json(['success' => false, 'error' => 'Keine Suchanfrage'], 400);
return;
}
if ($category !== '') {
$results = $this->searchService->searchByTaxonomy($query, $category, $limit);
} else {
$results = $this->searchService->search($query, $limit);
}
$this->json([
'success' => true,
'data' => $results,
'meta' => [
'query' => $query,
'limit' => $limit,
'count' => count($results),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.search] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/docs/hierarchy
* Vollständiger Dokumentationsbaum.
*/
public function hierarchy(): void
{
try {
$tree = $this->repository->getTree();
$this->json([
'success' => true,
'data' => $tree,
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.hierarchy] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* POST /api/v1/docs/chat
* Chat mit Dokumentation (RAG).
*/
public function chat(): void
{
try {
$input = $this->getJsonInput();
$question = trim($input['question'] ?? '');
$model = $input['model'] ?? 'mistral';
$limit = (int) ($input['limit'] ?? 5);
if ($question === '') {
$this->json(['success' => false, 'error' => 'Keine Frage angegeben'], 400);
return;
}
$result = $this->chatUseCase->execute($question, $model, $limit);
$this->json([
'success' => true,
'data' => $result,
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Docs.chat] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
}