Backup #2068

ID2068
Dateipfad/var/www/dev.campus.systemische-tools.de/src/UseCases/Search/EnhancedSearchUseCase.php
Version4
Typ modified
Größe7.2 KB
Hash18d43925b949fc6f2d37d4e1cd4bb1fe8252c52a2db6553d1ba88d9c6f75db90
Datum2025-12-28 23:32:02
Geändert vonclaude-code-hook
GrundClaude Code Pre-Hook Backup vor Edit-Operation
Datei existiert Ja

Dateiinhalt

<?php

declare(strict_types=1);

namespace UseCases\Search;

// @responsibility: Erweiterte Suche mit Taxonomie-Term-ID-Filterung

use Domain\Repository\ChunkTaxonomyRepositoryInterface;
use Domain\Repository\TaxonomyRepositoryInterface;
use Domain\Service\SearchServiceInterface;

final class EnhancedSearchUseCase
{
    public function __construct(
        private SearchServiceInterface $searchService,
        private ChunkTaxonomyRepositoryInterface $chunkTaxonomyRepository,
        private TaxonomyRepositoryInterface $taxonomyRepository
    ) {
    }

    /**
     * Enhanced search with taxonomy term ID filtering.
     *
     * @param string $query Search query
     * @param array<int> $taxonomyTermIds Filter by these taxonomy term IDs
     * @param bool $includeChildTerms Include child terms in filter (recursive)
     * @param int $limit Maximum results
     * @return array{
     *     results: array<array<string, mixed>>,
     *     taxonomy_filter: array{term_ids: array<int>, chunk_ids: array<int>},
     *     total_before_filter: int,
     *     total_after_filter: int
     * }
     */
    public function execute(
        string $query,
        array $taxonomyTermIds = [],
        bool $includeChildTerms = false,
        int $limit = 10
    ): array {
        // If no taxonomy filter, delegate directly to search service
        if (empty($taxonomyTermIds)) {
            $results = $this->searchService->search($query, [], $limit);

            return [
                'results' => $results,
                'taxonomy_filter' => ['term_ids' => [], 'chunk_ids' => []],
                'total_before_filter' => count($results),
                'total_after_filter' => count($results),
            ];
        }

        // Expand term IDs if includeChildTerms is true
        $effectiveTermIds = $includeChildTerms
            ? $this->expandWithChildTerms($taxonomyTermIds)
            : $taxonomyTermIds;

        // Get chunk IDs that match the taxonomy filter
        $filteredChunkIds = $this->getChunkIdsForTerms($effectiveTermIds);

        if (empty($filteredChunkIds)) {
            return [
                'results' => [],
                'taxonomy_filter' => ['term_ids' => $effectiveTermIds, 'chunk_ids' => []],
                'total_before_filter' => 0,
                'total_after_filter' => 0,
            ];
        }

        // Perform search with higher limit to allow for filtering
        $searchResults = $this->searchService->search($query, [], $limit * 5);
        $totalBeforeFilter = count($searchResults);

        // Filter results to only include chunks matching taxonomy
        $filteredResults = array_filter(
            $searchResults,
            static fn (array $result): bool => in_array($result['chunk_id'] ?? 0, $filteredChunkIds, true)
        );

        // Re-index and limit
        $filteredResults = array_values($filteredResults);
        $limitedResults = array_slice($filteredResults, 0, $limit);

        return [
            'results' => $limitedResults,
            'taxonomy_filter' => [
                'term_ids' => $effectiveTermIds,
                'chunk_ids' => $filteredChunkIds,
            ],
            'total_before_filter' => $totalBeforeFilter,
            'total_after_filter' => count($filteredResults),
        ];
    }

    /**
     * Search within a specific taxonomy term and its children.
     *
     * @return array<array<string, mixed>>
     */
    public function searchInTaxonomy(string $query, int $termId, int $limit = 10): array
    {
        $result = $this->execute($query, [$termId], true, $limit);

        return $result['results'];
    }

    /**
     * Get search suggestions based on taxonomy structure.
     *
     * @return array{
     *     terms: array<array{id: int, name: string, chunk_count: int}>,
     *     suggested_filters: array<int>
     * }
     */
    public function getSuggestionsForQuery(string $query): array
    {
        // First, get search results without filter
        $results = $this->searchService->search($query, [], 20);

        if (empty($results)) {
            return ['terms' => [], 'suggested_filters' => []];
        }

        // Extract chunk IDs from results
        $chunkIds = array_map(
            static fn (array $r): int => (int) ($r['chunk_id'] ?? 0),
            $results
        );
        $chunkIds = array_filter($chunkIds);

        // Find common taxonomy terms for these chunks
        $termCounts = [];
        foreach ($chunkIds as $chunkId) {
            $mappings = $this->chunkTaxonomyRepository->findByChunkId($chunkId);
            foreach ($mappings as $mapping) {
                $termId = $mapping->getTaxonomyTermId();
                if (!isset($termCounts[$termId])) {
                    $termCounts[$termId] = 0;
                }
                $termCounts[$termId]++;
            }
        }

        // Sort by count and get top terms
        arsort($termCounts);
        $topTermIds = array_slice(array_keys($termCounts), 0, 5);

        // Get term details
        $terms = [];
        foreach ($topTermIds as $termId) {
            $term = $this->taxonomyRepository->find($termId);
            if ($term !== null) {
                $terms[] = [
                    'id' => $termId,
                    'name' => $term['name'],
                    'chunk_count' => $termCounts[$termId],
                ];
            }
        }

        return [
            'terms' => $terms,
            'suggested_filters' => $topTermIds,
        ];
    }

    /**
     * Expand term IDs to include all child terms.
     *
     * @param array<int> $termIds
     * @return array<int>
     */
    private function expandWithChildTerms(array $termIds): array
    {
        $allTerms = $this->taxonomyRepository->findAll();
        $expanded = $termIds;

        // Build parent-child map
        $childrenMap = [];
        foreach ($allTerms as $term) {
            $parentId = $term['parent_id'];
            if ($parentId !== null) {
                if (!isset($childrenMap[$parentId])) {
                    $childrenMap[$parentId] = [];
                }
                $childrenMap[$parentId][] = $term['id'];
            }
        }

        // Recursively add children
        $queue = $termIds;
        while (!empty($queue)) {
            $currentId = array_shift($queue);
            if (isset($childrenMap[$currentId])) {
                foreach ($childrenMap[$currentId] as $childId) {
                    if (!in_array($childId, $expanded, true)) {
                        $expanded[] = $childId;
                        $queue[] = $childId;
                    }
                }
            }
        }

        return $expanded;
    }

    /**
     * Get chunk IDs that have mappings to any of the given taxonomy terms.
     *
     * @param array<int> $termIds
     * @return array<int>
     */
    private function getChunkIdsForTerms(array $termIds): array
    {
        $chunkIds = [];

        foreach ($termIds as $termId) {
            $mappings = $this->chunkTaxonomyRepository->findByTaxonomyTermId($termId);
            foreach ($mappings as $mapping) {
                $chunkId = $mapping['chunk_id'];
                if ($chunkId > 0 && !in_array($chunkId, $chunkIds, true)) {
                    $chunkIds[] = $chunkId;
                }
            }
        }

        return $chunkIds;
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
2070 6 modified 7.4 KB 2025-12-28 23:32
2069 5 modified 7.3 KB 2025-12-28 23:32
2068 4 modified 7.2 KB 2025-12-28 23:32
1521 3 modified 7.2 KB 2025-12-25 20:19
1520 2 modified 7.2 KB 2025-12-25 20:19
1518 1 modified 7.3 KB 2025-12-25 20:17

← Zurück zur Übersicht