ExplorerController.php
- Pfad:
src/Controller/Api/ExplorerController.php - Namespace: Controller\Api
- Zeilen: 301 | Größe: 9,969 Bytes
- Geändert: 2025-12-30 03:15:33 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 95
- Dependencies: 80 (25%)
- LOC: 99 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 100 (10%)
Keine Issues gefunden.
Dependencies 13
- extends Framework\Controller
- trait Infrastructure\Traits\JsonDecodeTrait
- constructor Domain\Repository\DokumentExplorerRepositoryInterface
- constructor Domain\Repository\SeiteExplorerRepositoryInterface
- constructor Domain\Repository\ChunkExplorerRepositoryInterface
- constructor Domain\Service\SearchServiceInterface
- use Domain\Constants
- use Domain\Repository\ChunkExplorerRepositoryInterface
- use Domain\Repository\DokumentExplorerRepositoryInterface
- use Domain\Repository\SeiteExplorerRepositoryInterface
- use Domain\Service\SearchServiceInterface
- use Framework\Controller
- use Infrastructure\Traits\JsonDecodeTrait
Klassen 1
-
ExplorerControllerclass Zeile 17
Funktionen 11
-
__construct()public Zeile 26 -
stats()public Zeile 41 -
listDokumente()public Zeile 62 -
getDokument()public Zeile 81 -
listSeiten()public Zeile 109 -
getSeite()public Zeile 138 -
listChunks()public Zeile 175 -
getChunk()public Zeile 205 -
taxonomie()public Zeile 229 -
entities()public Zeile 248 -
suche()public Zeile 264
Versionen 45
-
v45
2025-12-28 23:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v44
2025-12-28 23:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v43
2025-12-28 23:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v42
2025-12-28 23:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v41
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v40
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v39
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v38
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v37
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v36
2025-12-28 23:29 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v35
2025-12-27 15:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v34
2025-12-27 15:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v33
2025-12-27 15:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v32
2025-12-27 15:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v31
2025-12-27 15:30 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v30
2025-12-25 17:49 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v29
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v28
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v27
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v26
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v25
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v24
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v23
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v22
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v21
2025-12-25 12:34 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v20
2025-12-25 12:33 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v19
2025-12-23 07:53 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v18
2025-12-23 04:43 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v17
2025-12-23 04:43 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v16
2025-12-23 04:43 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v15
2025-12-23 04:25 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v14
2025-12-22 22:18 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Write-Operation -
v13
2025-12-22 08:19 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v12
2025-12-22 08:18 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v11
2025-12-22 08:18 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v10
2025-12-22 08:18 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v9
2025-12-22 08:18 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v8
2025-12-22 08:16 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v7
2025-12-22 08:06 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v6
2025-12-22 08:06 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v5
2025-12-22 08:03 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v4
2025-12-22 08:03 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v3
2025-12-22 07:59 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v2
2025-12-22 07:59 | claude-code-hook | modified
Claude Code Pre-Hook Backup vor Edit-Operation -
v1
2025-12-20 17:24 | 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 Doc2Vector Explorer (Dokumente, Chunks, Suche)
use Domain\Constants;
use Domain\Repository\ChunkExplorerRepositoryInterface;
use Domain\Repository\DokumentExplorerRepositoryInterface;
use Domain\Repository\SeiteExplorerRepositoryInterface;
use Domain\Service\SearchServiceInterface;
use Framework\Controller;
use Infrastructure\Traits\JsonDecodeTrait;
class ExplorerController extends Controller
{
use JsonDecodeTrait;
private DokumentExplorerRepositoryInterface $dokumentRepository;
private SeiteExplorerRepositoryInterface $seiteRepository;
private ChunkExplorerRepositoryInterface $chunkRepository;
private SearchServiceInterface $searchService;
public function __construct(
DokumentExplorerRepositoryInterface $dokumentRepository,
SeiteExplorerRepositoryInterface $seiteRepository,
ChunkExplorerRepositoryInterface $chunkRepository,
SearchServiceInterface $searchService
) {
$this->dokumentRepository = $dokumentRepository;
$this->seiteRepository = $seiteRepository;
$this->chunkRepository = $chunkRepository;
$this->searchService = $searchService;
}
/**
* GET /api/v1/explorer/stats
*/
public function stats(): void
{
try {
$this->json([
'success' => true,
'data' => [
'dokumente' => $this->dokumentRepository->countDokumente(),
'seiten' => $this->seiteRepository->countSeiten(),
'chunks' => $this->chunkRepository->getChunkStats(),
'taxonomy_categories' => $this->chunkRepository->getTopTaxonomyCategories(Constants::DEFAULT_LIMIT),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.stats] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/dokumente
*/
public function listDokumente(): void
{
try {
$dokumente = $this->dokumentRepository->getDokumenteWithFullStats();
$this->json([
'success' => true,
'data' => $dokumente,
'meta' => ['total' => count($dokumente)],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.listDokumente] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/dokumente/{id}
*/
public function getDokument(string $id): void
{
try {
$dokument = $this->dokumentRepository->getDokumentRoot((int) $id);
if ($dokument === null) {
$this->json(['success' => false, 'error' => 'Dokument nicht gefunden'], 404);
return;
}
$this->json([
'success' => true,
'data' => [
'dokument' => $dokument,
'seiten' => $this->seiteRepository->getSeitenWithStatsForParent((int) $id),
'taxonomy' => $this->seiteRepository->getTaxonomyForDokumentTree((int) $id),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.getDokument] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/seiten
*/
public function listSeiten(): void
{
try {
$search = $this->getString('search');
$parentId = $this->getString('parent_id');
$limit = $this->getLimit(Constants::DEFAULT_LIMIT, Constants::PERCENT_HALF);
$offset = $this->getInt('offset');
$total = $this->seiteRepository->countSeitenFiltered($search, $parentId);
$seiten = $this->seiteRepository->getSeitenPaginated($search, $parentId, $limit, $offset);
$this->json([
'success' => true,
'data' => $seiten,
'meta' => [
'total' => $total,
'limit' => $limit,
'offset' => $offset,
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.listSeiten] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/seiten/{id}
*/
public function getSeite(string $id): void
{
try {
$seite = $this->seiteRepository->getSeiteWithParent((int) $id);
if ($seite === null) {
$this->json(['success' => false, 'error' => 'Seite nicht gefunden'], 404);
return;
}
$chunks = $this->chunkRepository->getChunksDetailedForDokument((int) $id);
// Decode JSON fields in chunks
foreach ($chunks as &$c) {
$c['entities'] = $this->decodeJsonArray($c['entities'] ?? null);
$c['keywords'] = $this->decodeJsonArray($c['keywords'] ?? null);
$c['taxonomy_path'] = $this->decodeJsonArray($c['taxonomy_path'] ?? null);
}
$this->json([
'success' => true,
'data' => [
'seite' => $seite,
'chunks' => $chunks,
'unterseiten' => $this->seiteRepository->getUnterseiten((int) $id),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.getSeite] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/chunks
*/
public function listChunks(): void
{
try {
$category = $this->getString('category');
$status = $this->getString('status');
$search = $this->getString('search');
$limit = $this->getLimit(Constants::DEFAULT_LIMIT, Constants::PERCENT_HALF);
$offset = $this->getInt('offset');
$total = $this->chunkRepository->countChunksFiltered($category, $status, $search);
$chunks = $this->chunkRepository->getChunksFilteredPaginated($category, $status, $search, $limit, $offset);
$this->json([
'success' => true,
'data' => $chunks,
'meta' => [
'total' => $total,
'limit' => $limit,
'offset' => $offset,
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.listChunks] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/chunks/{id}
*/
public function getChunk(string $id): void
{
try {
$chunk = $this->chunkRepository->getChunk((int) $id);
if ($chunk === null) {
$this->json(['success' => false, 'error' => 'Chunk nicht gefunden'], 404);
return;
}
$this->json([
'success' => true,
'data' => $chunk,
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.getChunk] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/taxonomie
*/
public function taxonomie(): void
{
try {
$this->json([
'success' => true,
'data' => [
'categories' => $this->chunkRepository->getTopTaxonomyCategories(Constants::DEFAULT_LIMIT),
'top_keywords' => $this->chunkRepository->getTopKeywords(50),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.taxonomie] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* GET /api/v1/explorer/entities
*/
public function entities(): void
{
try {
$this->json([
'success' => true,
'data' => $this->chunkRepository->getEntitiesGrouped(Constants::DEFAULT_LIMIT),
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.entities] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
/**
* POST /api/v1/explorer/suche
*/
public function suche(): void
{
try {
$input = $this->getJsonInput();
$query = trim($input['query'] ?? '');
if ($query === '') {
$this->json(['success' => false, 'error' => 'Query ist erforderlich'], 400);
return;
}
$filters = [];
if (!empty($input['category'])) {
$filters['taxonomy_category'] = $input['category'];
}
$limit = min((int) ($input['limit'] ?? 10), 50);
$results = $this->searchService->search($query, $filters, $limit);
$suggestions = $this->searchService->suggestRelatedSearches($results);
$this->json([
'success' => true,
'data' => [
'query' => $query,
'results' => $results,
'suggestions' => $suggestions,
'count' => count($results),
],
]);
} catch (\Exception $e) {
error_log(sprintf('[API.Explorer.suche] %s: %s', get_class($e), $e->getMessage()));
$this->jsonError($e->getMessage());
}
}
}