AssignChunkTaxonomyUseCase.php

Code Hygiene Score: 95

Keine Issues gefunden.

Dependencies 11

Klassen 1

Funktionen 7

Versionen 1

Code

<?php

declare(strict_types=1);

namespace UseCases\Taxonomy;

// @responsibility: Manuelle und automatische Chunk-Taxonomie-Zuweisung

use Domain\Entity\ChunkTaxonomyMapping;
use Domain\Repository\ChunkExplorerRepositoryInterface;
use Domain\Repository\ChunkTaxonomyRepositoryInterface;
use Domain\Repository\TaxonomyRepositoryInterface;
use Domain\ValueObject\Confidence;
use Domain\ValueObject\MappingSource;
use Infrastructure\Audit\AuditService;

final class AssignChunkTaxonomyUseCase
{
    public function __construct(
        private ChunkTaxonomyRepositoryInterface $chunkTaxonomyRepository,
        private ChunkExplorerRepositoryInterface $chunkRepository,
        private TaxonomyRepositoryInterface $taxonomyRepository,
        private AuditService $auditService
    ) {
    }

    /**
     * Assign a single taxonomy term to a chunk.
     *
     * @throws \InvalidArgumentException if validation fails
     */
    public function execute(
        int $chunkId,
        int $taxonomyTermId,
        float $confidence,
        string $source
    ): int {
        $this->validateChunk($chunkId);
        $this->validateTaxonomyTerm($taxonomyTermId);
        $this->validateConfidence($confidence);
        $this->validateSource($source);

        // Check if mapping already exists
        if ($this->chunkTaxonomyRepository->exists($chunkId, $taxonomyTermId)) {
            throw new \InvalidArgumentException(
                "Mapping already exists for chunk {$chunkId} and term {$taxonomyTermId}"
            );
        }

        $mapping = new ChunkTaxonomyMapping();
        $mapping->setChunkId($chunkId);
        $mapping->setTaxonomyTermId($taxonomyTermId);
        $mapping->setConfidence(Confidence::fromFloat($confidence));
        $mapping->setSource(MappingSource::from($source));

        $id = $this->chunkTaxonomyRepository->save($mapping);

        $this->auditService->logCreate(
            table: 'chunk_taxonomy',
            id: $id,
            data: [
                'chunk_id' => $chunkId,
                'taxonomy_term_id' => $taxonomyTermId,
                'confidence' => $confidence,
                'source' => $source,
            ],
            actor: 'system',
            actorType: $source === 'auto' ? 'pipeline' : 'user'
        );

        return $id;
    }

    /**
     * Batch assign taxonomy terms to chunks.
     *
     * @param array<array{chunk_id: int, taxonomy_term_id: int, confidence: float, source: string}> $assignments
     * @return array{success: int, errors: array<string>}
     */
    public function batchAssign(array $assignments): array
    {
        $successCount = 0;
        $errors = [];

        foreach ($assignments as $index => $assignment) {
            try {
                $this->execute(
                    chunkId: $assignment['chunk_id'],
                    taxonomyTermId: $assignment['taxonomy_term_id'],
                    confidence: $assignment['confidence'],
                    source: $assignment['source']
                );
                $successCount++;
            } catch (\Exception $e) {
                $errors[] = "Assignment {$index}: " . $e->getMessage();
            }
        }

        return [
            'success' => $successCount,
            'errors' => $errors,
        ];
    }

    private function validateChunk(int $chunkId): void
    {
        $chunk = $this->chunkRepository->getChunk($chunkId);
        if ($chunk === null) {
            throw new \InvalidArgumentException("Chunk {$chunkId} not found");
        }
    }

    private function validateTaxonomyTerm(int $termId): void
    {
        $term = $this->taxonomyRepository->find($termId);
        if ($term === null) {
            throw new \InvalidArgumentException("Taxonomy term {$termId} not found");
        }
    }

    private function validateConfidence(float $confidence): void
    {
        if ($confidence < 0.0 || $confidence > 1.0) {
            throw new \InvalidArgumentException(
                "Confidence must be between 0.0 and 1.0, got {$confidence}"
            );
        }
    }

    private function validateSource(string $source): void
    {
        $validSources = ['auto', 'manual'];
        if (!in_array($source, $validSources, true)) {
            throw new \InvalidArgumentException(
                "Invalid source '{$source}'. Must be one of: " . implode(', ', $validSources)
            );
        }
    }
}
← Übersicht Graph