['page'], 'product' => ['product'], 'hotel' => ['hotel'], 'destination' => ['region', 'country', 'city'], 'concept' => ['concept'], 'news' => ['news'], ]; private const TYPE_WEIGHTS = [ 'product' => 1.4, 'hotel' => 1.4, 'region' => 1.2, 'country' => 1.2, 'city' => 1.2, 'concept' => 1.2, 'page' => 1.0, 'news' => 0.8, ]; public function __construct(private readonly ContentDocumentRepository $repository) { } /** * @param string|null $type a key of TYPES * * @return list */ public function search(string $query, ?string $type, ?string $site, int $limit): array { $booleanQuery = ContentSearchQuery::booleanQuery($query); if (null === $booleanQuery) { return []; } $rows = $this->repository->searchFulltext($booleanQuery, null === $type ? [] : self::TYPES[$type], $site, self::TYPE_WEIGHTS, $limit); $terms = ContentSearchQuery::terms($query); return array_map(static fn (array $row): array => [ 'type' => self::publicType($row['type']), 'title' => $row['title'], 'url' => $row['url'], 'site' => $row['site'], 'breadcrumb' => $row['breadcrumb'], 'excerpt' => Excerpt::around($row['body_md'], $terms), ], $rows); } /** * The tool's name for a stored type. */ public static function publicType(string $type): string { foreach (self::TYPES as $public => $types) { if (in_array($type, $types, true)) { return $public; } } return $type; } }