src/Service/SearchService.php line 35

  1. <?php
  2. namespace App\Service;
  3. use App\Dto\SearchResult;
  4. use App\Entity\Coleccion;
  5. use App\Entity\Composicion;
  6. use App\Entity\Destacada;
  7. use App\Entity\Modelo;
  8. use App\Entity\Programa;
  9. use App\Repository\ColeccionRepository;
  10. use App\Repository\ComposicionRepository;
  11. use App\Repository\DestacadaRepository;
  12. use App\Repository\ModeloRepository;
  13. use App\Repository\ProgramaRepository;
  14. class SearchService
  15. {
  16.     public function __construct(
  17.         private ModeloRepository $modeloRepository,
  18.         private ColeccionRepository $coleccionRepository,
  19.         private ComposicionRepository $composicionRepository,
  20.         private ProgramaRepository $programaRepository,
  21.         private DestacadaRepository $destacadaRepository
  22.     ) {}
  23.     /**
  24.      * Realiza una búsqueda global en todas las entidades
  25.      * 
  26.      * @param string $term Término de búsqueda
  27.      * @param int $finalLimit Límite de resultados finales
  28.      * @param int $perEntityLimit Límite de resultados por entidad (para ordenar después)
  29.      * @return SearchResult[]
  30.      */
  31.     public function globalSearch(string $termint $finalLimit 10int $perEntityLimit null): array
  32.     {
  33.         // Si no se especifica límite por entidad, usar el triple del límite final
  34.         $perEntityLimit $perEntityLimit ?? ($finalLimit 3);
  35.         
  36.         $results = [];
  37.         // Buscar en Modelos
  38.         $modelos $this->modeloRepository->searchByTerm($term$perEntityLimit);
  39.         foreach ($modelos as $modelo) {
  40.             $results[] = $this->createSearchResultFromModelo($modelo);
  41.         }
  42.         // Buscar en Colecciones
  43.         $colecciones $this->coleccionRepository->searchByTerm($term$perEntityLimit);
  44.         foreach ($colecciones as $coleccion) {
  45.             $results[] = $this->createSearchResultFromColeccion($coleccion);
  46.         }
  47.         // Buscar en Composiciones
  48.         $composiciones $this->composicionRepository->searchByTerm($term$perEntityLimit);
  49.         foreach ($composiciones as $composicion) {
  50.             $results[] = $this->createSearchResultFromComposicion($composicion);
  51.         }
  52.         // Buscar en Programas
  53.         $programas $this->programaRepository->searchByTerm($term$perEntityLimit);
  54.         foreach ($programas as $programa) {
  55.             $results[] = $this->createSearchResultFromPrograma($programa);
  56.         }
  57.         // Buscar en Destacadas
  58.         $destacadas $this->destacadaRepository->searchByTerm($term$perEntityLimit);
  59.         foreach ($destacadas as $destacada) {
  60.             $results[] = $this->createSearchResultFromDestacada($destacada);
  61.         }
  62.         // Ordenar resultados por relevancia
  63.         usort($results, function (SearchResult $aSearchResult $b) use ($term) {
  64.             $termLower strtolower($term);
  65.             $aNameLower strtolower($a->getNombre());
  66.             $bNameLower strtolower($b->getNombre());
  67.             $aDescLower strtolower($a->getDescripcion() ?? '');
  68.             $bDescLower strtolower($b->getDescripcion() ?? '');
  69.             // 1. Coincidencia exacta en el nombre
  70.             $aExact = ($aNameLower === $termLower) ? 0;
  71.             $bExact = ($bNameLower === $termLower) ? 0;
  72.             if ($aExact !== $bExact) {
  73.                 return $bExact $aExact;
  74.             }
  75.             // 2. Comienza con el término en el nombre
  76.             $aStarts str_starts_with($aNameLower$termLower) ? 0;
  77.             $bStarts str_starts_with($bNameLower$termLower) ? 0;
  78.             if ($aStarts !== $bStarts) {
  79.                 return $bStarts $aStarts;
  80.             }
  81.             // 3. Contiene el término en el nombre (antes que en descripción)
  82.             $aInName str_contains($aNameLower$termLower) ? 0;
  83.             $bInName str_contains($bNameLower$termLower) ? 0;
  84.             if ($aInName !== $bInName) {
  85.                 return $bInName $aInName;
  86.             }
  87.             // 4. Contiene el término en la descripción (menor prioridad)
  88.             $aInDesc str_contains($aDescLower$termLower) ? 0;
  89.             $bInDesc str_contains($bDescLower$termLower) ? 0;
  90.             if ($aInDesc !== $bInDesc) {
  91.                 return $bInDesc $aInDesc;
  92.             }
  93.             // 5. Orden alfabético
  94.             return strcmp($aNameLower$bNameLower);
  95.         });
  96.         // Limitar los resultados finales
  97.         return array_slice($results0$finalLimit);
  98.     }
  99.     private function createSearchResultFromModelo(Modelo $modelo): SearchResult
  100.     {
  101.         return new SearchResult(
  102.             type'modelo',
  103.             id$modelo->getId(),
  104.             nombre$modelo->getNombre(),
  105.             descripcion$modelo->getDescripcion(),
  106.             metadata: [
  107.                 'coleccion' => $modelo->getColeccion()?->getNombre(),
  108.                 'ancho' => $modelo->getAncho(),
  109.                 'alto' => $modelo->getAlto(),
  110.                 'fondo' => $modelo->getFondo(),
  111.             ]
  112.         );
  113.     }
  114.     private function createSearchResultFromColeccion(Coleccion $coleccion): SearchResult
  115.     {
  116.         return new SearchResult(
  117.             type'coleccion',
  118.             id$coleccion->getId(),
  119.             nombre$coleccion->getNombre(),
  120.             descripcion$coleccion->getDescripcion(),
  121.             metadata: [
  122.                 'programa' => $coleccion->getPrograma()?->getNombre(),
  123.             ]
  124.         );
  125.     }
  126.     private function createSearchResultFromComposicion(Composicion $composicion): SearchResult
  127.     {
  128.         return new SearchResult(
  129.             type'composicion',
  130.             id$composicion->getId(),
  131.             nombre$composicion->getNombre(),
  132.             descripcionnull,
  133.             metadata: [
  134.                 'modelo' => $composicion->getModelo()?->getNombre(),
  135.                 'precio' => $composicion->getPrecio(),
  136.             ]
  137.         );
  138.     }
  139.     private function createSearchResultFromPrograma(Programa $programa): SearchResult
  140.     {
  141.         return new SearchResult(
  142.             type'programa',
  143.             id$programa->getId(),
  144.             nombre$programa->getNombre(),
  145.             descripcion$programa->getDescripcion(),
  146.             metadata: []
  147.         );
  148.     }
  149.     private function createSearchResultFromDestacada(Destacada $destacada): SearchResult
  150.     {
  151.         return new SearchResult(
  152.             type'destacada',
  153.             id$destacada->getId(),
  154.             nombre$destacada->getNombre(),
  155.             descripcionnull,
  156.             metadata: [
  157.                 'activo' => $destacada->getActivo(),
  158.             ]
  159.         );
  160.     }
  161. }