ExplorerController.php

Code Hygiene Score: 95

Keine Issues gefunden.

Dependencies 13

Klassen 1

Funktionen 11

Versionen 45

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());
        }
    }
}
← Übersicht Graph