exec('PRAGMA foreign_keys = ON;'); return $db; } /** * Make sure the expected tables exist */ public static function ensureDb(): void { $db = self::getConnection(); $tables = array(); $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' CREATE TABLE frc_user ( id INTEGER NOT NULL PRIMARY KEY, email TEXT NOT NULL, password TEXT NOT NULL) SQL; $db->exec($query); $db->exec('CREATE INDEX idx_user_email ON frc_user (email)'); } if (!in_array('feed', $tables)) { $query = <<<'SQL' CREATE TABLE feed ( id INTEGER NOT NULL PRIMARY KEY, user_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT, updated_on TEXT, checked_on TEXT, FOREIGN KEY (user_id) REFERENCES frc_user (id)) SQL; $db->exec($query); } if (!in_array('item', $tables)) { $query = <<<'SQL' CREATE TABLE item ( id INTEGER NOT NULL PRIMARY KEY, feed_id INTEGER NOT NULL, title TEXT NOT NULL, item_guid TEXT NOT NULL, item_link TEXT NOT NULL, published_on TEXT NOT NULL, updated_on TEXT, content TEXT NOT NULL, 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); } $db->close(); } /** * Parse/format a date/time from a string * * @param ?string $value The date/time to be parsed and formatted * @return string|null The date/time in `DateTimeInterface::ATOM` format, or `null` if the input cannot be parsed */ public static function formatDate(?string $value): ?string { try { return $value ? (new DateTimeImmutable($value))->format(DateTimeInterface::ATOM) : null; } catch (Exception) { return null; } } /** * Return the last SQLite error message as a result array * * @param SQLite3 $db The database connection on which the error has occurred * @return string[] ['error' => message] for last SQLite error message */ public static function error(SQLite3 $db): array { return ['error' => 'SQLite error: ' . $db->lastErrorMsg()]; } }