1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries\Search;
7
8class MultiSearch
9{
10 const MODES = [
11 'all' => null,
12 'user' => [
13 'type' => UserSearch::class,
14 'paramsType' => UserSearchRequestParams::class,
15 'size' => 6,
16 ],
17 'beatmapset' => [
18 'type' => BeatmapsetSearch::class,
19 'paramsType' => BeatmapsetSearchRequestParams::class,
20 'size' => 8,
21 ],
22 'wiki_page' => [
23 'type' => WikiSearch::class,
24 'paramsType' => WikiSearchRequestParams::class,
25 'size' => 8,
26 ],
27 'forum_post' => [
28 'type' => ForumSearch::class,
29 'paramsType' => ForumSearchRequestParams::class,
30 'size' => 8,
31 ],
32 ];
33
34 private $options;
35 private $query;
36 private $searches;
37
38 public function __construct(private array $request, array $options = [])
39 {
40 if (isset($this->request['mode'])) {
41 $this->request['mode'] = presence(get_string($this->request['mode']));
42 }
43 if (isset($this->request['query'])) {
44 $this->request['query'] = get_string($this->request['query']);
45 }
46 if (isset($this->request['username'])) {
47 $this->request['username'] = presence(get_string($this->request['username']));
48 }
49 $this->query = trim($this->request['query'] ?? '');
50 $this->options = $options;
51 }
52
53 public function getMode()
54 {
55 return $this->request['mode'] ?? 'all';
56 }
57
58 public function getRawQuery(): ?string
59 {
60 return $this->request['query'] ?? null;
61 }
62
63 public function hasQuery()
64 {
65 return present($this->query)
66 || ($this->getMode() === 'forum_post' && isset($this->request['username']));
67 }
68
69 public function searches()
70 {
71 if (!isset($this->searches)) {
72 $this->searches = [];
73 $error = null;
74
75 foreach (static::MODES as $mode => $settings) {
76 if ($settings === null) {
77 $this->searches[$mode] = null;
78 continue;
79 }
80
81 $class = $settings['type'];
82 $paramsClass = $settings['paramsType'];
83
84 $params = new $paramsClass($this->request, $this->options['user']);
85 $search = new $class($params);
86 if ($search instanceof BeatmapsetSearch) {
87 $search->source(false);
88 }
89
90 if ($error !== null) {
91 $search->fail($error);
92 } else {
93 if ($this->getMode() === 'all') {
94 $search->from(0)->size($settings['size']);
95 if ($this->hasQuery()) {
96 $search->response(); // FIXME: run query before counts for tab; need better way to do this.
97 }
98 } elseif ($this->getMode() === $mode) {
99 if ($this->hasQuery()) {
100 $search->response(); // FIXME: run query before counts for tab; need better way to do this.
101 }
102 }
103
104 $error = $search->getError();
105 }
106
107 $this->searches[$mode] = $search;
108 }
109 }
110
111 return $this->searches;
112 }
113}