searchTermParser = new SearchTermParser(); $this->db = $database; } /** * @param string $searchTerm * @param array|null $projectIds Projekt-IDs die der Benutzer aufrufen darf; * null = Keine Einschränkung (nur bei Admins) * @param array|null $moduleNames Module die der Benutzer aufrufen darf; * null = Keine Einschränkung (nur bei Admins) * @param int $resultLimit Anzahl der Ergebnisse * * @throws InvalidArgumentException * * @return ResultCollection */ public function search($searchTerm, array $projectIds = null, array $moduleNames = null, $resultLimit = 30) { $resultLimit = (int)$resultLimit; if ($resultLimit < 1) { throw new InvalidArgumentException('Parameter value $resultLimit is invalid.'); } $searchTerm = $this->searchTermParser->parse($searchTerm); // Ergebnisse mit Projekt-ID 0 immer anzeigen (z.b. Appstore-Ergebnisse) if (is_array($projectIds) && !in_array(0, $projectIds, true)) { $projectIds[] = 0; } if (is_array($moduleNames) && !in_array('appstore', $moduleNames, true)) { $moduleNames[] = 'appstore'; } $sqlProjects = ''; $sqlModules = ''; $bindValues = [ 'search_term' => $searchTerm, 'result_limit' => $resultLimit, ]; if ($projectIds !== null) { $sqlProjects = ' AND sii.project_id IN (:project_ids) '; $bindValues['project_ids'] = (array)$projectIds; } if ($moduleNames !== null) { $sqlModules = ' AND (sig.module IN (:module_names) OR sig.module IS NULL) '; $bindValues['module_names'] = (array)$moduleNames; } $sql = "SELECT sii.index_name, sii.index_id, sig.title AS `index_title`, sii.project_id, sii.title, sii.subtitle, sii.additional_infos, sii.link, sii.search_words FROM `supersearch_index_item` AS `sii` INNER JOIN `supersearch_index_group` AS `sig` ON sii.index_name = sig.name WHERE MATCH (sii.search_words) AGAINST (:search_term IN BOOLEAN MODE) {$sqlProjects} {$sqlModules} AND sii.outdated = 0 AND sig.active = 1 LIMIT 0, :result_limit"; $data = $this->db->fetchAll($sql, $bindValues); return $this->buildResultCollection($data); } /** * @param array $data * * @return ResultCollection */ private function buildResultCollection($data) { $lastIndexUpdate = $this->getRecentIndexTime(); $results = new ResultCollection([], $lastIndexUpdate); foreach ($data as $item) { if (!$results->hasGroup($item['index_name'])) { $results->addGroup(new ResultGroup($item['index_name'], $item['index_title'])); } /** @var ResultGroup $group */ $group = $results->getGroup($item['index_name']); $group->addItem(ResultItem::fromDbState($item)); } return $results; } /** * Liefert den Zeitpunkt wann der Index das letzte Mal aktualisiert wurde * * @return DateTimeInterface|null */ private function getRecentIndexTime() { $sql = 'SELECT MAX(GREATEST(IFNULL(sig.last_full_update, 1), IFNULL(sig.last_diff_update, 1))) AS `last_update` FROM `supersearch_index_group` AS sig WHERE sig.active = 1'; $value = $this->db->fetchValue($sql); if (empty($value)) { return null; } try { $dateTime = new DateTimeImmutable($value); } catch (Exception $exception) { return null; } return $dateTime; } }