<?php /** * A centralized place for data access for the application */ class Data { /** * Obtain a new connection to the database * @return SQLite3 A new connection to the database */ private static function getConnection(): SQLite3 { $db = new SQLite3('../data/' . DATABASE_NAME); $db->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, published_on TEXT NOT NULL, updated_on TEXT, content TEXT NOT NULL, is_encoded BOOLEAN NOT NULL, is_read BOOLEAN NOT NULL, is_bookmarked BOOLEAN NOT NULL, FOREIGN KEY (feed_id) REFERENCES feed (id)) SQL; $db->exec($query); } $db->close(); } /** * Find a user by their ID * * @param string $email The e-mail address of the user to retrieve * @return array|null The user information, or null if the user is not found */ public static function findUserByEmail(string $email): ?array { $db = self::getConnection(); $query = $db->prepare('SELECT * FROM frc_user WHERE email = :email'); $query->bindValue(':email', $email); $result = $query->execute(); if ($result) { $user = $result->fetchArray(SQLITE3_ASSOC); if ($user) return $user; return null; } return null; } /** * Add a user * * @param string $email The e-mail address for the user * @param string $password The user's password */ public static function addUser(string $email, string $password): void { $db = self::getConnection(); $query = $db->prepare('INSERT INTO frc_user (email, password) VALUES (:email, :password)'); $query->bindValue(':email', $email); $query->bindValue(':password', password_hash($password, PASSWORD_DEFAULT)); $query->execute(); } /** * Add an RSS feed * @param string $url The URL for the RSS feed * @param string $title The title of the RSS feed * @param string $updatedOn The date/time the RSS feed was last updated (from the XML, not when we checked) * @return int The ID of the added feed */ public static function addFeed(string $url, string $title, string $updatedOn): int { $db = self::getConnection(); if ($updatedOn) { try { $updated = (new DateTimeImmutable($updatedOn))->format(DateTimeInterface::ATOM); } catch (Exception $ex) { $updated = null; } } else { $updated = null; } $query = $db->prepare('INSERT INTO feed (user_id, url, title, updated_on, checked_on)' . ' VALUES (:user, :url, :title, :updated, :checked)'); $query->bindValue(':user', $_REQUEST['FRC_USER_ID']); $query->bindValue(':url', $url); $query->bindValue(':title', $title); $query->bindValue(':updated', $updated); $query->bindValue(':checked', (new DateTimeImmutable())->format(DateTimeInterface::ATOM)); $result = $query->execute(); if ($result) { $idQuery = $db->prepare('SELECT last_insert_rowid()'); $idResult = $idQuery->execute(); if ($idResult) return $idResult->fetchArray(SQLITE3_NUM)[0]; } return -1; } }