{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/UseCases\/Search\/EnhancedSearchUseCase.php",
"oldString": " \/**\n * Search within a specific taxonomy term and its children.\n *\n * @return array<array<string, mixed>>\n *\/",
"newString": " \/**\n * Search within a specific taxonomy term and its children.\n *\n * @return array<array<string, mixed>>\n *\n * @throws \\RuntimeException When search service or repository operations fail\n *\/",
"originalFile": "<?php\n\ndeclare(strict_types=1);\n\nnamespace UseCases\\Search;\n\n\/\/ @responsibility: Erweiterte Suche mit Taxonomie-Term-ID-Filterung\n\nuse Domain\\Repository\\ChunkTaxonomyRepositoryInterface;\nuse Domain\\Repository\\TaxonomyRepositoryInterface;\nuse Domain\\Service\\SearchServiceInterface;\n\nfinal class EnhancedSearchUseCase\n{\n public function __construct(\n private SearchServiceInterface $searchService,\n private ChunkTaxonomyRepositoryInterface $chunkTaxonomyRepository,\n private TaxonomyRepositoryInterface $taxonomyRepository\n ) {\n }\n\n \/**\n * Enhanced search with taxonomy term ID filtering.\n *\n * @param string $query Search query\n * @param array<int> $taxonomyTermIds Filter by these taxonomy term IDs\n * @param bool $includeChildTerms Include child terms in filter (recursive)\n * @param int $limit Maximum results\n * @return array{\n * results: array<array<string, mixed>>,\n * taxonomy_filter: array{term_ids: array<int>, chunk_ids: array<int>},\n * total_before_filter: int,\n * total_after_filter: int\n * }\n *\n * @throws \\RuntimeException When search service or repository operations fail\n *\/\n public function execute(\n string $query,\n array $taxonomyTermIds = [],\n bool $includeChildTerms = false,\n int $limit = 10\n ): array {\n \/\/ If no taxonomy filter, delegate directly to search service\n if (empty($taxonomyTermIds)) {\n $results = $this->searchService->search($query, [], $limit);\n\n return [\n 'results' => $results,\n 'taxonomy_filter' => ['term_ids' => [], 'chunk_ids' => []],\n 'total_before_filter' => count($results),\n 'total_after_filter' => count($results),\n ];\n }\n\n \/\/ Expand term IDs if includeChildTerms is true\n $effectiveTermIds = $includeChildTerms\n ? $this->expandWithChildTerms($taxonomyTermIds)\n : $taxonomyTermIds;\n\n \/\/ Get chunk IDs that match the taxonomy filter\n $filteredChunkIds = $this->getChunkIdsForTerms($effectiveTermIds);\n\n if (empty($filteredChunkIds)) {\n return [\n 'results' => [],\n 'taxonomy_filter' => ['term_ids' => $effectiveTermIds, 'chunk_ids' => []],\n 'total_before_filter' => 0,\n 'total_after_filter' => 0,\n ];\n }\n\n \/\/ Perform search with higher limit to allow for filtering\n $searchResults = $this->searchService->search($query, [], $limit * 5);\n $totalBeforeFilter = count($searchResults);\n\n \/\/ Filter results to only include chunks matching taxonomy\n $filteredResults = array_filter(\n $searchResults,\n static fn (array $result): bool => in_array($result['chunk_id'] ?? 0, $filteredChunkIds, true)\n );\n\n \/\/ Re-index and limit\n $filteredResults = array_values($filteredResults);\n $limitedResults = array_slice($filteredResults, 0, $limit);\n\n return [\n 'results' => $limitedResults,\n 'taxonomy_filter' => [\n 'term_ids' => $effectiveTermIds,\n 'chunk_ids' => $filteredChunkIds,\n ],\n 'total_before_filter' => $totalBeforeFilter,\n 'total_after_filter' => count($filteredResults),\n ];\n }\n\n \/**\n * Search within a specific taxonomy term and its children.\n *\n * @return array<array<string, mixed>>\n *\/\n public function searchInTaxonomy(string $query, int $termId, int $limit = 10): array\n {\n $result = $this->execute($query, [$termId], true, $limit);\n\n return $result['results'];\n }\n\n \/**\n * Get search suggestions based on taxonomy structure.\n *\n * @return array{\n * terms: array<array{id: int, name: string, chunk_count: int}>,\n * suggested_filters: array<int>\n * }\n *\/\n public function getSuggestionsForQuery(string $query): array\n {\n \/\/ First, get search results without filter\n $results = $this->searchService->search($query, [], 20);\n\n if (empty($results)) {\n return ['terms' => [], 'suggested_filters' => []];\n }\n\n \/\/ Extract chunk IDs from results\n $chunkIds = array_map(\n static fn (array $r): int => (int) ($r['chunk_id'] ?? 0),\n $results\n );\n $chunkIds = array_filter($chunkIds);\n\n \/\/ Find common taxonomy terms for these chunks\n $termCounts = [];\n foreach ($chunkIds as $chunkId) {\n $mappings = $this->chunkTaxonomyRepository->findByChunkId($chunkId);\n foreach ($mappings as $mapping) {\n $termId = $mapping->getTaxonomyTermId();\n if (!isset($termCounts[$termId])) {\n $termCounts[$termId] = 0;\n }\n $termCounts[$termId]++;\n }\n }\n\n \/\/ Sort by count and get top terms\n arsort($termCounts);\n $topTermIds = array_slice(array_keys($termCounts), 0, 5);\n\n \/\/ Get term details\n $terms = [];\n foreach ($topTermIds as $termId) {\n $term = $this->taxonomyRepository->find($termId);\n if ($term !== null) {\n $terms[] = [\n 'id' => $termId,\n 'name' => $term['name'],\n 'chunk_count' => $termCounts[$termId],\n ];\n }\n }\n\n return [\n 'terms' => $terms,\n 'suggested_filters' => $topTermIds,\n ];\n }\n\n \/**\n * Expand term IDs to include all child terms.\n *\n * @param array<int> $termIds\n * @return array<int>\n *\/\n private function expandWithChildTerms(array $termIds): array\n {\n $allTerms = $this->taxonomyRepository->findAll();\n $expanded = $termIds;\n\n \/\/ Build parent-child map\n $childrenMap = [];\n foreach ($allTerms as $term) {\n $parentId = $term['parent_id'];\n if ($parentId !== null) {\n if (!isset($childrenMap[$parentId])) {\n $childrenMap[$parentId] = [];\n }\n $childrenMap[$parentId][] = $term['id'];\n }\n }\n\n \/\/ Recursively add children\n $queue = $termIds;\n while (!empty($queue)) {\n $currentId = array_shift($queue);\n if (isset($childrenMap[$currentId])) {\n foreach ($childrenMap[$currentId] as $childId) {\n if (!in_array($childId, $expanded, true)) {\n $expanded[] = $childId;\n $queue[] = $childId;\n }\n }\n }\n }\n\n return $expanded;\n }\n\n \/**\n * Get chunk IDs that have mappings to any of the given taxonomy terms.\n *\n * @param array<int> $termIds\n * @return array<int>\n *\/\n private function getChunkIdsForTerms(array $termIds): array\n {\n $chunkIds = [];\n\n foreach ($termIds as $termId) {\n $mappings = $this->chunkTaxonomyRepository->findByTaxonomyTermId($termId);\n foreach ($mappings as $mapping) {\n $chunkId = $mapping['chunk_id'];\n if ($chunkId > 0 && !in_array($chunkId, $chunkIds, true)) {\n $chunkIds[] = $chunkId;\n }\n }\n }\n\n return $chunkIds;\n }\n}\n",
"structuredPatch": [
{
"oldStart": 99,
"oldLines": 6,
"newStart": 99,
"newLines": 8,
"lines": [
" * Search within a specific taxonomy term and its children.",
" *",
" * @return array<array<string, mixed>>",
"+ *",
"+ * @throws \\RuntimeException When search service or repository operations fail",
" *\/",
" public function searchInTaxonomy(string $query, int $termId, int $limit = 10): array",
" {"
]
}
],
"userModified": false,
"replaceAll": false
}
}