feat(search): ✨ add proper DB tag searching
This commit is contained in:
parent
f9cfb81079
commit
22c953793c
4 changed files with 147 additions and 20 deletions
|
@ -80,6 +80,16 @@ interface PostdataInterface {
|
||||||
$order_by = 'path');
|
$order_by = 'path');
|
||||||
|
|
||||||
public function get_post_markdown($id);
|
public function get_post_markdown($id);
|
||||||
|
|
||||||
|
|
||||||
|
// Returns an array of PostData information
|
||||||
|
// based on the tag search list
|
||||||
|
//
|
||||||
|
// Tag searchlist is comprised of space-separated
|
||||||
|
// tags. Each tag can have a weighting prefix,
|
||||||
|
// and some special tags exist (such as limit:N,
|
||||||
|
// order:S).
|
||||||
|
public function search_posts($taglist);
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
|
@ -3,23 +3,7 @@
|
||||||
require_once 'analytics_interface.php';
|
require_once 'analytics_interface.php';
|
||||||
require_once 'db_interface.php';
|
require_once 'db_interface.php';
|
||||||
|
|
||||||
function taglist_escape_tag($tag) {
|
require_once 'mysql_taglist_handling.php';
|
||||||
return preg_replace_callback('/[\WZ]/', function($match) {
|
|
||||||
return "Z" . ord($match[0]);
|
|
||||||
}, strtolower($tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
function taglist_to_sql_string($post_tags) {
|
|
||||||
$post_tags = array_unique($post_tags);
|
|
||||||
$post_tags = array_map(function($val) {
|
|
||||||
return taglist_escape_tag($val);
|
|
||||||
}, $post_tags);
|
|
||||||
|
|
||||||
asort($post_tags);
|
|
||||||
$post_tags = join(' ', $post_tags);
|
|
||||||
|
|
||||||
return $post_tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MySQLHandler
|
class MySQLHandler
|
||||||
implements PostdataInterface {
|
implements PostdataInterface {
|
||||||
|
@ -128,7 +112,7 @@ class MySQLHandler
|
||||||
$post_path,
|
$post_path,
|
||||||
substr_count($post_path, "/"),
|
substr_count($post_path, "/"),
|
||||||
$data['title'],
|
$data['title'],
|
||||||
taglist_to_sql_string($post_tags),
|
TagList\create_db_str($post_tags),
|
||||||
$data['brief'] ?? null
|
$data['brief'] ?? null
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -292,8 +276,8 @@ class MySQLHandler
|
||||||
'path DESC' => true,
|
'path DESC' => true,
|
||||||
'created_at' => true,
|
'created_at' => true,
|
||||||
'created_at DESC' => true,
|
'created_at DESC' => true,
|
||||||
'modified_at' => true,
|
'updated_at' => true,
|
||||||
'modified_at DESC' => true
|
'updated_at DESC' => true
|
||||||
];
|
];
|
||||||
|
|
||||||
if(!isset($allowed_ordering[$order_by])) {
|
if(!isset($allowed_ordering[$order_by])) {
|
||||||
|
@ -342,6 +326,52 @@ class MySQLHandler
|
||||||
|
|
||||||
return $data['post_markdown'];
|
return $data['post_markdown'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function search_posts($taglist) {
|
||||||
|
$qry = "
|
||||||
|
SELECT *
|
||||||
|
FROM posts
|
||||||
|
WHERE MATCH(post_tags) AGAINST (? IN BOOLEAN MODE)
|
||||||
|
";
|
||||||
|
|
||||||
|
$search_data = TagList\create_db_search($taglist);
|
||||||
|
|
||||||
|
$order_by = $search_data['modifiers']['order_by'] ?? 'updated_at';
|
||||||
|
$limit = intval($search_data['modifiers']['limit'] ?? 20);
|
||||||
|
$offset = intval($search_data['modifiers']['offset'] ?? 0);
|
||||||
|
|
||||||
|
if($limit > 100) {
|
||||||
|
throw new Exception('Search limit above maximum (max 100 results per search)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed_ordering = [
|
||||||
|
'path' => true,
|
||||||
|
'path DESC' => true,
|
||||||
|
'created_at' => true,
|
||||||
|
'created_at DESC' => true,
|
||||||
|
'updated_at' => true,
|
||||||
|
'updated_at DESC' => true
|
||||||
|
];
|
||||||
|
// TODO move this to a class var
|
||||||
|
|
||||||
|
if(!isset($allowed_ordering[$order_by])) {
|
||||||
|
throw new Exception('Search order not allowed');
|
||||||
|
}
|
||||||
|
$order_by = 'post_' . $order_by;
|
||||||
|
|
||||||
|
$qry = $qry . " ORDER BY " . $order_by . " LIMIT ? OFFSET ?";
|
||||||
|
|
||||||
|
$search_results = $this->_exec($qry, "sii", $search_data['parameter_string'],
|
||||||
|
$limit, $offset)->fetch_all(MYSQLI_ASSOC);
|
||||||
|
|
||||||
|
$outdata = [];
|
||||||
|
foreach($search_results AS $post_element) {
|
||||||
|
$outdata []=
|
||||||
|
$this->process_postdata($post_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $outdata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
76
www/src/db_handler/mysql_taglist_handling.php
Normal file
76
www/src/db_handler/mysql_taglist_handling.php
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
namespace TagList;
|
||||||
|
|
||||||
|
function escape_entry($tag) {
|
||||||
|
return preg_replace_callback('/[\WZ]/', function($match) {
|
||||||
|
return "Z" . ord($match[0]);
|
||||||
|
}, strtolower($tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape_search_entry($tag) {
|
||||||
|
preg_match("/^([\+\-]?)([^\*]*)(\*?)$/", $tag, $matches);
|
||||||
|
|
||||||
|
if(!isset($matches[1])) {
|
||||||
|
echo "Problem with tag!";
|
||||||
|
var_dump($tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $matches[1] . escape_entry($matches[2]) . $matches[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _str_to_raw_taglist($taglist) {
|
||||||
|
$split_list = explode(' ', $taglist);
|
||||||
|
|
||||||
|
$split_list = array_filter($split_list, function($entry) {
|
||||||
|
return !preg_match('/^\s*$/', $entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $split_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_db_str($taglist) {
|
||||||
|
if(gettype($taglist) == 'string') {
|
||||||
|
$taglist = _str_to_raw_taglist($taglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
$taglist = array_unique($taglist);
|
||||||
|
$taglist = array_map(function($val) {
|
||||||
|
return escape_entry($val);
|
||||||
|
}, $taglist);
|
||||||
|
|
||||||
|
asort($taglist);
|
||||||
|
$taglist = join(' ', $taglist);
|
||||||
|
|
||||||
|
return $taglist;
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_db_search($taglist) {
|
||||||
|
if(gettype($taglist) == 'string') {
|
||||||
|
$taglist = _str_to_raw_taglist($taglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_params = [];
|
||||||
|
$search_modifiers = [];
|
||||||
|
|
||||||
|
foreach($taglist as $tag) {
|
||||||
|
if(preg_match('/^(order|limit):(.*)$/i', $tag, $match)) {
|
||||||
|
$search_modifiers[$match[1]] = $match[2];
|
||||||
|
} else {
|
||||||
|
array_push($search_params, $tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_params = array_map(function($val) {
|
||||||
|
return escape_search_entry($val);
|
||||||
|
}, $search_params);
|
||||||
|
|
||||||
|
asort($search_params);
|
||||||
|
$search_params = join(' ', $search_params);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'modifiers' => $search_modifiers,
|
||||||
|
'parameter_string' => $search_params
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -56,6 +56,17 @@ class PostHandler {
|
||||||
|
|
||||||
return $out_list;
|
return $out_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function search_posts($search_query) {
|
||||||
|
$search_results = $this->db->search_posts($search_query);
|
||||||
|
|
||||||
|
$out_list = [];
|
||||||
|
foreach($search_results as $search_result) {
|
||||||
|
array_push($out_list, new Post($this, $search_result, $this->site_defaults));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out_list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
Loading…
Add table
Add a link
Reference in a new issue