Alpha 7 #22
|
@ -14,6 +14,31 @@ class Data {
|
|||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the search index and synchronization triggers for the item table
|
||||
*
|
||||
* @param SQLite3 $db The database connection on which these will be created
|
||||
*/
|
||||
public static function createSearchIndex(SQLite3 $db): void {
|
||||
$db->exec("CREATE VIRTUAL TABLE item_search USING fts5(content, content='item', content_rowid='id')");
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TRIGGER item_ai AFTER INSERT ON item BEGIN
|
||||
INSERT INTO item_search (rowid, content) VALUES (new.id, new.content);
|
||||
END;
|
||||
SQL);
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TRIGGER item_au AFTER UPDATE ON item BEGIN
|
||||
INSERT INTO item_search (item_search, rowid, content) VALUES ('delete', old.id, old.content);
|
||||
INSERT INTO item_search (rowid, content) VALUES (new.id, new.content);
|
||||
END;
|
||||
SQL);
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TRIGGER item_ad AFTER DELETE ON item BEGIN
|
||||
INSERT INTO item_search (item_search, rowid, content) VALUES ('delete', old.id, old.content);
|
||||
END;
|
||||
SQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the expected tables exist
|
||||
*/
|
||||
|
@ -23,17 +48,16 @@ class Data {
|
|||
$tableQuery = $db->query("SELECT name FROM sqlite_master WHERE type = 'table'");
|
||||
while ($table = $tableQuery->fetchArray(SQLITE3_NUM)) $tables[] = $table[0];
|
||||
if (!in_array('frc_user', $tables)) {
|
||||
$query = <<<'SQL'
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TABLE frc_user (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
email TEXT NOT NULL,
|
||||
password TEXT NOT NULL)
|
||||
SQL;
|
||||
$db->exec($query);
|
||||
SQL);
|
||||
$db->exec('CREATE INDEX idx_user_email ON frc_user (email)');
|
||||
}
|
||||
if (!in_array('feed', $tables)) {
|
||||
$query = <<<'SQL'
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TABLE feed (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
|
@ -42,11 +66,10 @@ class Data {
|
|||
updated_on TEXT,
|
||||
checked_on TEXT,
|
||||
FOREIGN KEY (user_id) REFERENCES frc_user (id))
|
||||
SQL;
|
||||
$db->exec($query);
|
||||
SQL);
|
||||
}
|
||||
if (!in_array('item', $tables)) {
|
||||
$query = <<<'SQL'
|
||||
$db->exec(<<<'SQL'
|
||||
CREATE TABLE item (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
feed_id INTEGER NOT NULL,
|
||||
|
@ -59,8 +82,8 @@ class Data {
|
|||
is_read BOOLEAN NOT NULL DEFAULT 0,
|
||||
is_bookmarked BOOLEAN NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY (feed_id) REFERENCES feed (id))
|
||||
SQL;
|
||||
$db->exec($query);
|
||||
SQL);
|
||||
self::createSearchIndex($db);
|
||||
}
|
||||
$db->close();
|
||||
}
|
||||
|
|
|
@ -134,6 +134,22 @@ class ItemList {
|
|||
"/feed/items?id=$feedId&bookmarked");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an item list with items matching given search terms
|
||||
*
|
||||
* @param string $search The item search terms / query
|
||||
* @param SQLite3 $db The database connection to use to obtain items
|
||||
* @return static An item list match the given search terms
|
||||
*/
|
||||
public static function matchingSearch(string $search, SQLite3 $db): static {
|
||||
$list = new static($db,
|
||||
self::makeQuery($db, ['item.id IN (SELECT ROWID FROM item_search WHERE content MATCH :search)'],
|
||||
[[':search', $search]]), 'Matching', "/search?search=$search");
|
||||
$list->showIndicators = true;
|
||||
$list->displayFeed = true;
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this item list
|
||||
*/
|
||||
|
|
23
src/public/search.php
Normal file
23
src/public/search.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Item Search Page
|
||||
*
|
||||
* Search for items across all feeds
|
||||
*/
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
|
||||
if (key_exists('search', $_GET)) {
|
||||
$list = ItemList::matchingSearch($_GET['search'], $db);
|
||||
}
|
||||
|
||||
page_head('Item Search'); ?>
|
||||
<h1>Item Search</h1>
|
||||
// TODO: search form <?php
|
||||
if (isset($list)) $list->render();
|
||||
page_foot();
|
||||
$db->close();
|
|
@ -67,7 +67,8 @@ function title_bar(): void {
|
|||
$hasBookmarks = $bookResult && $bookResult->fetchArray(SQLITE3_NUM)[0];
|
||||
echo hx_get('/feeds', 'Feeds') . ' | ';
|
||||
if ($hasBookmarks) echo hx_get('/?bookmarked', 'Bookmarked') . ' | ';
|
||||
echo hx_get('/docs/', 'Docs') . ' | <a href=/user/log-off>Log Off</a>';
|
||||
echo hx_get('/search', 'Search') . ' | ' . hx_get('/docs/', 'Docs')
|
||||
. ' | <a href=/user/log-off>Log Off</a>';
|
||||
if ($_SESSION[Key::USER_EMAIL] != Security::SINGLE_USER_EMAIL) {
|
||||
echo " | {$_SESSION[Key::USER_EMAIL]}";
|
||||
}
|
||||
|
|
49
src/util/search.php
Normal file
49
src/util/search.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
|
||||
require __DIR__ . '/../cli-start.php';
|
||||
|
||||
cli_title('SEARCH MAINTENANCE');
|
||||
|
||||
if ($argc < 2) display_help();
|
||||
|
||||
switch ($argv[1]) {
|
||||
case 'rebuild':
|
||||
rebuild_index();
|
||||
break;
|
||||
default:
|
||||
printfn('Unrecognized option "%s"', $argv[1]);
|
||||
display_help();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the options for this utility and exit
|
||||
*/
|
||||
#[NoReturn]
|
||||
function display_help(): void {
|
||||
printfn('Options:');
|
||||
printfn(' - rebuild');
|
||||
printfn(' Rebuilds search index');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the search index, creating it if it does not already exist
|
||||
*/
|
||||
function rebuild_index(): void {
|
||||
$db = Data::getConnection();
|
||||
|
||||
try {
|
||||
$hasIndex = $db->query("SELECT COUNT(*) FROM sqlite_master WHERE name = 'item_ai'");
|
||||
if ($hasIndex->fetchArray(SQLITE3_NUM)[0] == 0) {
|
||||
printfn('Creating search index....');
|
||||
Data::createSearchIndex($db);
|
||||
}
|
||||
printfn('Rebuilding search index...');
|
||||
$db->exec("INSERT INTO item_search (item_search) VALUES ('rebuild')");
|
||||
printfn(PHP_EOL . 'Search index rebuilt');
|
||||
} finally {
|
||||
$db->close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user