diff --git a/endpoints/search/DELETE.php b/endpoints/search/DELETE.php new file mode 100644 index 0000000..9dc485a --- /dev/null +++ b/endpoints/search/DELETE.php @@ -0,0 +1,35 @@ +ruleset = new Ruleset(strict: true); + + $this->ruleset->POST([ + (new Rules(SearchTable::ID->value)) + ->required() + ->type(Type::STRING) + ->min(2) + ->max(parent::SIZE_VARCHAR) + ]); + + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + public function main(): Response { + return $this->db->for(SearchTable::NAME)->delete($_POST) === true ? new Response() : new Response("", 500); + } + } \ No newline at end of file diff --git a/endpoints/search/GET.php b/endpoints/search/GET.php index 7eccbed..16b12cd 100644 --- a/endpoints/search/GET.php +++ b/endpoints/search/GET.php @@ -1,12 +1,16 @@ ruleset->GET([ (new Rules(SearchTable::QUERY->value)) - ->required() ->type(Type::STRING) ->min(2) ->max(parent::SIZE_VARCHAR) + ->default(null), + + (new Rules(SearchTable::ID->value)) + ->type(Type::STRING) + ->min(10) + ->max(10) + ->default(null), + + (new Rules(SearchTable::CATEGORY->value)) + ->type(Type::ENUM, SearchCategoryEnum::names()) + ->default(null), + + (new Rules(SEARCH_UPDATE_CACHE_PARM)) + ->type(Type::BOOLEAN) + ->default(false) ]); $this->ruleset->validate_or_exit(); @@ -29,20 +47,47 @@ parent::__construct(); } + private static function get_query(): string { + preg_match_all("/[a-zA-Z0-9]+/", $_GET[SearchTable::QUERY->value], $matches); + + return strtolower(implode("", $matches[0])); + } + public function main(): Response { - $result = $this->db - ->for(SearchTable::NAME) - ->where([ + // Freshen cache if update flag is set + if ($_GET[SEARCH_UPDATE_CACHE_PARM]) { + (new Call(Endpoints::SEARCH->value))->post(); + } + + $result = $this->db->for(SearchTable::NAME); + + if ($_GET[SearchTable::ID->value]) { + $result = $result->where([SearchTable::ID->value => $_GET[SearchTable::ID->value]]); + } else if ($_GET[SearchTable::QUERY->value]) { + $query = self::get_query(); + + $filter = [ SearchTable::QUERY->value => [ - Operators::LIKE->value => "%{$_GET[SearchTable::QUERY->value]}%" + Operators::LIKE->value => "%{$query}%" ] - ]) - ->select([ - SearchTable::TITLE->value, - SearchTable::SUMMARY->value, - SearchTable::CATEGORY->value, - SearchTable::HREF->value - ]); + ]; + + if ($_GET[SearchTable::CATEGORY->value]) { + $filter[SearchTable::CATEGORY->value] = $_GET[SearchTable::CATEGORY->value]; + } + + $result = $result->where($filter); + } else { + new Response([], 400); + } + + $result = $result->select([ + SearchTable::ID->value, + SearchTable::TITLE->value, + SearchTable::SUMMARY->value, + SearchTable::CATEGORY->value, + SearchTable::HREF->value + ]); return $result->num_rows > 0 ? new Response($result->fetch_all(MYSQLI_ASSOC)) diff --git a/endpoints/search/POST.php b/endpoints/search/POST.php new file mode 100644 index 0000000..107d627 --- /dev/null +++ b/endpoints/search/POST.php @@ -0,0 +1,73 @@ +ruleset = new Ruleset(strict: true); + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + private static function truncate_string(string $input): string { + return substr($input, 0, SEARCH_QUERY_MAX_LENGTH); + } + + private static function create_query(string $input): string { + preg_match_all("/[a-zA-Z0-9]+/", $input, $matches); + + return self::truncate_string(strtolower(implode("", $matches[0]))); + } + + private function index_work(): void { + foreach ((new Call(Endpoints::WORK->value))->get()->output() as $result) { + $query = self::create_query(implode("", array_values($result)), 0, SEARCH_QUERY_MAX_LENGTH); + + // Get actions related to current result + $actions = (new Call(Endpoints::WORK_ACTIONS->value))->params([ + ActionsTable::REF_WORK_ID->value => $result[WorkTable::ID->value] + ])->get()->output(); + + $this->db->for(SearchTable::NAME)->insert([ + SearchTable::QUERY->value => $query, + SearchTable::ID->value => crc32($query), + SearchTable::TITLE->value => self::truncate_string($result[WorkTable::TITLE->value]), + SearchTable::SUMMARY->value => self::truncate_string($result[WorkTable::SUMMARY->value]), + SearchTable::CATEGORY->value => SearchCategoryEnum::WORK->name, + // Use first action as link for search result + SearchTable::HREF->value => $actions + ? self::truncate_string($actions[0][ActionsTable::HREF->value]) + : null + ]); + } + } + + public function main(): Response { + // Truncate existing cache + (new Call(Endpoints::SEARCH->value))->delete(); + + $this->index_work(); + + return $result->num_rows > 0 + ? new Response($result->fetch_all(MYSQLI_ASSOC)) + : new Response([], 404); + } + } \ No newline at end of file diff --git a/public/assets/css/pages/search.css b/public/assets/css/pages/search.css index 640b15a..13440a2 100644 --- a/public/assets/css/pages/search.css +++ b/public/assets/css/pages/search.css @@ -54,4 +54,11 @@ section.start-search { section.start-search svg { width: 60px; +} + +/* # Result */ + +section.result { + padding: var(--padding); + background-color: rgba(255, 255, 255, .1); } \ No newline at end of file diff --git a/public/search.php b/public/search.php index 52c81e9..0f85750 100644 --- a/public/search.php +++ b/public/search.php @@ -1,7 +1,7 @@ value => self::get_query()]); + return parent::all([SearchTable::QUERY->value => self::get_query()]); } } @@ -30,7 +30,6 @@
value, $_GET)): ?> -= $result->summary() ?>
+ + href()): ?> + + +