diff --git a/src/Controller/SearchController.php b/src/Controller/SearchController.php index ab98cd7..7734181 100644 --- a/src/Controller/SearchController.php +++ b/src/Controller/SearchController.php @@ -21,7 +21,7 @@ final class SearchController extends AbstractController $filters = $request->getPayload(); } - $results = $searchService->searchSites($filters); + $results = $searchService->search($filters); return $this->json($results); } diff --git a/src/DTO/SearchResult.php b/src/DTO/SearchResult.php new file mode 100644 index 0000000..89310e9 --- /dev/null +++ b/src/DTO/SearchResult.php @@ -0,0 +1,31 @@ + $sites + * @param array<\App\Entity\NotConserved> $notConserved + * @param array<\App\Entity\Finding> $findings + * @param array<\App\Entity\Underwater> $underwater + */ + public function __construct( + public array $sites, + public array $notConserved, + public array $findings, + public array $underwater, + ) {} + + public function jsonSerialize(): array + { + return [ + "sites" => $this->sites, + "notConserved" => $this->notConserved, + "findings" => $this->findings, + "underwater" => $this->underwater, + ]; + } +} \ No newline at end of file diff --git a/src/Entity/Finding.php b/src/Entity/Finding.php index 99aecae..408e8b3 100644 --- a/src/Entity/Finding.php +++ b/src/Entity/Finding.php @@ -55,6 +55,9 @@ class Finding implements \JsonSerializable #[ORM\Column(name: 'etichetta', length: 150, nullable: false)] private ?string $label = null; + #[ORM\Column(name: 'categoria', length: 100, nullable: true)] + private ?string $category = null; + private ?float $lat = null; private ?float $lng = null; @@ -237,6 +240,18 @@ class Finding implements \JsonSerializable return $this; } + public function getCategory(): ?string + { + return $this->category; + } + + public function setCategory(?string $category): static + { + $this->category = $category; + + return $this; + } + public function getLat(): ?float { return $this->lat; @@ -285,6 +300,15 @@ class Finding implements \JsonSerializable return $this; } + // Needed for search results purposes + public function toSummary(): array + { + return [ + 'id' => $this->id, + 'label' => $this->label, + ]; + } + public function jsonSerialize(): array { return [ diff --git a/src/Enum/FindingCategoryEnum.php b/src/Enum/FindingCategoryEnum.php new file mode 100644 index 0000000..d05fdfc --- /dev/null +++ b/src/Enum/FindingCategoryEnum.php @@ -0,0 +1,12 @@ +executeQuery($sql, ['id' => $id]) ->fetchAssociative(); } - // /** - // * @return Finding[] Returns an array of Finding objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('f') - // ->andWhere('f.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('f.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } + /** + * For the search endpoint + * @see SearchService + * @return Finding[] Returns an array of Finding objects + */ + public function findByFilters(array $filters): array + { + $qb = $this->createQueryBuilder('s'); + + if (!empty($filters['text'])) { + $qb->andWhere('LOWER(s.label) LIKE :text OR LOWER(s.object) LIKE :text'); + $qb->setParameter('text', $filters['text']); + } + + if (!empty($filters['category'])) { + $qb->andWhere('LOWER(s.category) = :category'); + $qb->setParameter('category', $filters['category']); + } + + $qb->orderBy('s.label', 'ASC'); + $query = $qb->getQuery(); + + return $query->getResult(); + } + /** + * @return Finding[] Returns an array of Finding objects + */ + public function findByCategory(string $value): array + { + return $this->createQueryBuilder('f') + ->andWhere('f.category = :val') + ->setParameter('val', $value) + ->orderBy('f.label', 'ASC') + ->getQuery() + ->getResult() + ; + } // public function findOneBySomeField($value): ?Finding // { diff --git a/src/Repository/SiteRepository.php b/src/Repository/SiteRepository.php index 61dae70..feafc01 100644 --- a/src/Repository/SiteRepository.php +++ b/src/Repository/SiteRepository.php @@ -57,8 +57,6 @@ class SiteRepository extends ServiceEntityRepository $qb->orderBy('s.label', 'ASC'); $query = $qb->getQuery(); - //dd($query, $filters['text']); - return $query->getResult(); } diff --git a/src/Service/SearchService.php b/src/Service/SearchService.php index ce81dd0..8adb641 100644 --- a/src/Service/SearchService.php +++ b/src/Service/SearchService.php @@ -4,28 +4,54 @@ declare(strict_types=1); namespace App\Service; -use App\Repository\SiteRepository; +use App\Repository\{ + SiteRepository, + FindingRepository, + NotConservedRepository, + UnderwaterRepository +}; use App\Enum\OpusEnum; -use App\Enum\SitesCategoryEnum; use App\Exception\InvalidFilterException; +use App\DTO\SearchResult; +use App\Enum\FindingCategoryEnum; use function Symfony\Component\String\u; final class SearchService { - public function __construct(private readonly SiteRepository $siteRepository) {} + public function __construct( + private readonly SiteRepository $siteRepository, + private readonly FindingRepository $findingRepository, + ) {} - public function searchSites(array $rawFilters): array + public function search(array $rawFilters): SearchResult { $filters = $this->normalizeFilters($rawFilters); // No results should be returned if no filter is valid - if (empty($filters)) return []; + if (empty($filters)) return new SearchResult([], [], [], []); - return array_map( - fn(\App\Entity\Site $s) => $s->toSummary(), - $this->siteRepository->findByFilters($filters) + $sites = []; + if (!(count($filters) === 1 && isset($filters['category']))) { + $sites = array_map( + fn(\App\Entity\Site $s) => $s->toSummary(), + $this->siteRepository->findByFilters($filters) + ); + } + + $findings = array_map( + fn(\App\Entity\Finding $f) => $f->toSummary(), + $this->findingRepository->findByFilters($filters) ); + + $result = new SearchResult( + sites: $sites, + notConserved: [], + findings: $findings, + underwater: [], + ); + + return $result; } /** * @throws InvalidFilterException @@ -42,13 +68,15 @@ final class SearchService } // Prepare for LIKE query (useful?) - $filters['text'] = $text !== '' ? '%' . u($text)->lower()->toUnicodeString() . '%' : ''; + if (isset($filters['text'])) { + $filters['text'] = $text !== '' ? '%' . u($text)->lower()->toUnicodeString() . '%' : ''; + } if (!empty($filters['technique']) && OpusEnum::tryFrom($filters['technique']) === null) { throw new InvalidFilterException("Invalid technique filter: " . $filters['technique']); } - if (!empty($filters['category']) && SitesCategoryEnum::tryFrom($filters['category']) === null) { + if (!empty($filters['category']) && FindingCategoryEnum::tryFrom($filters['category']) === null) { throw new InvalidFilterException("Invalid category filter: " . $filters['category']); }