From a65d424263adfbff9629c7d91a613e4504c84613 Mon Sep 17 00:00:00 2001 From: Jonas Kohl Date: Tue, 17 Sep 2024 14:51:23 +0200 Subject: Add search --- src/application/i18n.php | 2 +- src/application/messages/de.msg | 20 +++++++++ src/application/mystic/forum/Database.php | 27 ++++++++++++ src/application/views/form_search.php | 28 +++++++++++++ src/application/views/nav_guest.php | 1 + src/application/views/nav_logged_in.php | 1 + src/application/views/view_search_results.php | 33 +++++++++++++++ src/index.php | 59 +++++++++++++++++++++++++++ 8 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/application/views/form_search.php create mode 100644 src/application/views/view_search_results.php diff --git a/src/application/i18n.php b/src/application/i18n.php index a1f2f24..a7bdd82 100644 --- a/src/application/i18n.php +++ b/src/application/i18n.php @@ -173,7 +173,7 @@ function i18n_get(string $msgid, array $params = [], ?string $context = null): s if ($context !== null) $key = $context . "\x7F" . $msgid; - $msg = ($__i18n_msg_store[$__i18n_current_locale] ?? [])[$msgid] ?? $key; + $msg = ($__i18n_msg_store[$__i18n_current_locale] ?? [])[$key] ?? $msgid; uksort($params, fn(string $a, string $b): int => strlen($b) <=> strlen($a)); return str_replace( diff --git a/src/application/messages/de.msg b/src/application/messages/de.msg index ed8178e..784c257 100644 --- a/src/application/messages/de.msg +++ b/src/application/messages/de.msg @@ -5,6 +5,14 @@ metadata({ } }) +: "." +? "Number formatting" += "," + +: "," +? "Number formatting" += "." + : "Log in" = "Anmelden" @@ -318,3 +326,15 @@ metadata({ : "Language:" = "Sprache:" + +: "Search" += "Suche" + +: "Search results for “%query%”" += "Suchergebnisse für „%query%“" + +: "No results for this search" += "Keine Ergebnisse für diese Suche" + +: "%result_count% result(s) in %search_duration% second(s)" += "%result_count% Treffer in %search_duration% Sekunde(n)" diff --git a/src/application/mystic/forum/Database.php b/src/application/mystic/forum/Database.php index a1e67ea..8ebc36b 100644 --- a/src/application/mystic/forum/Database.php +++ b/src/application/mystic/forum/Database.php @@ -414,6 +414,33 @@ class Database { return $items; } + public function execCustomQuery(string $query, ?array $customQueryParams = null, ?string $entityClassName = null): array { + if ($customQueryParams === null) + $result = \pg_query($this->connection, $query); + else + $result = \pg_query_params($this->connection, $query, $customQueryParams); + if ($result === false) + throw new \RuntimeException("Query failed: " . \pg_last_error($this->connection)); + $cols = null; + if ($entityClassName !== null) { + $reflClass = new ReflectionClass($entityClassName); + $cols = self::getColumns($reflClass); + } + $rowsOrItems = []; + while (($row = \pg_fetch_assoc($result)) !== false) { + if ($entityClassName !== null) { + $entity = new $entityClassName(); + foreach ($cols as $colName => $colProps) + self::assignValue($entity, $colProps, $row[$colName]); + $rowsOrItems []= $entity; + } else { + $rowsOrItems []= $row; + } + } + \pg_free_result($result); + return $rowsOrItems; + } + public function delete(Entity &$entity): bool { $entityClassName = get_class($entity); $tableName = self::getTableName($entityClassName); diff --git a/src/application/views/form_search.php b/src/application/views/form_search.php new file mode 100644 index 0000000..edc68b8 --- /dev/null +++ b/src/application/views/form_search.php @@ -0,0 +1,28 @@ + + + $_formError]); +} +?> +
" method="post"> +
+
+ " required autofocus> +
+ +
+
+
+
diff --git a/src/application/views/nav_guest.php b/src/application/views/nav_guest.php index 1c65a50..88c551b 100644 --- a/src/application/views/nav_guest.php +++ b/src/application/views/nav_guest.php @@ -1,4 +1,5 @@ diff --git a/src/application/views/view_search_results.php b/src/application/views/view_search_results.php new file mode 100644 index 0000000..19a6978 --- /dev/null +++ b/src/application/views/view_search_results.php @@ -0,0 +1,33 @@ + + + 0): ?> +

count($posts), + "search_duration" => number_format($search_duration, 2, __(".", context: "Number formatting"), __(",", context: "Number formatting")), + ]) ?>

+
+ deleted) continue; + $hasAttachments = count($attachments[$post->id]) > 0; + ?> + + + + + content)), 100)) ?>
+ '' . htmlentities($users[$post->authorId]?->displayName ?? __("unknown")) . '', + "post_date" => '' . htmlentities($post->postDate->format("c")) . '', + "topic" => '' . htmlentities($topics[$post->topicId]?->title ?? "unknown") . '', + ]) ?> +
+ +
+ +
+ + +
+ diff --git a/src/index.php b/src/index.php index 1b13e97..f3a59b2 100644 --- a/src/index.php +++ b/src/index.php @@ -1139,6 +1139,65 @@ if ($_action === "auth") { } header("Location: ./?_action=viewtopic&topic=" . urlencode($topicId)); +} elseif ($_action === "search") { + if (RequestUtils::isRequestMethod("POST")) { + $query = RequestUtils::getRequiredField("query"); + /** @var Post[] $posts */ + + $start_time = microtime(true); + $posts = $db->execCustomQuery(<<topicId])) { + $topic = new Topic; + $topic->id = $post->topicId; + if ($db->fetch($topic)) + $topicLookup[$topic->id] = &$topic; + } + if (!isset($attachmentLookup[$post->id])) { + $attachmentLookup[$post->id] = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]); + } + if (!isset($userLookup[$post->authorId])) { + $user = new User; + $user->id = $post->authorId; + if ($db->fetch($user)) + $userLookup[$post->authorId] = &$user; + } + } + $end_time = microtime(true); + $search_duration = $end_time - $start_time; + + _view("template_start", ["_title" => __("Search results for “%query%”", [ "query" => $query ])]); + _view("template_navigation_start"); + _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); + _view("template_navigation_end"); + _view("form_search", [ "query" => $query ]); + _view("view_search_results", [ + "posts" => &$posts, + "topics" => &$topicLookup, + "users" => &$userLookup, + "attachments" => &$attachmentLookup, + "search_duration" => $search_duration, + ]); + _view("template_end", [...getThemeAndLangInfo()]); + } else { + _view("template_start", ["_title" => __("Search")]); + _view("template_navigation_start"); + _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); + _view("template_navigation_end"); + _view("form_search"); + _view("template_end", [...getThemeAndLangInfo()]); + } } elseif ($_action === "captcha") { $phrase = generateCaptchaText(); $builder = new CaptchaBuilder($phrase); -- cgit v1.2.3