From 832b7b95fa3cda147b77439aa2bace5facff1fe9 Mon Sep 17 00:00:00 2001 From: Greg Sarjeant Date: Sun, 3 Aug 2025 19:15:24 +0000 Subject: [PATCH] Remove all static model methods. (#52) Replace all static model methods. Support dependency injection for all models. Clean up things that used the static model methods. Decouple ConfigModel and CssModel. Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/52 Co-authored-by: Greg Sarjeant Co-committed-by: Greg Sarjeant --- public/index.php | 4 +-- src/Controller/Controller.php | 10 +++++++ .../CssController/CssController.php | 12 ++++---- .../EmojiController/EmojiController.php | 30 ++++++++++++++----- .../MoodController/MoodController.php | 9 ++++-- src/Model/ConfigModel/ConfigModel.php | 23 ++------------ src/Model/CssModel/CssModel.php | 25 +++++++--------- src/Model/EmojiModel/EmojiModel.php | 20 +++++-------- src/Model/UserModel/UserModel.php | 12 ++------ templates/main.php | 3 +- 10 files changed, 73 insertions(+), 75 deletions(-) diff --git a/public/index.php b/public/index.php index 0882d52..7cc587a 100644 --- a/public/index.php +++ b/public/index.php @@ -72,8 +72,8 @@ global $app; $app = [ 'db' => $db, - 'config' => (new ConfigModel($db))->loadFromDatabase(), - 'user' => (new UserModel($db))->loadFromDatabase(), + 'config' => (new ConfigModel($db))->get(), + 'user' => (new UserModel($db))->get(), ]; // Start a session and generate a CSRF Token diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php index 043acf2..5b1b7de 100644 --- a/src/Controller/Controller.php +++ b/src/Controller/Controller.php @@ -13,6 +13,16 @@ class Controller { throw new RuntimeException("Template not found: $childTemplatePath"); } + // Add custom CSS filename if needed + global $app; + if ($app['config']->cssId) { + $cssModel = new CssModel($app['db']); + $cssFile = $cssModel->getById($app['config']->cssId); + $vars['customCssFilename'] = $cssFile['filename'] ?? null; + } else { + $vars['customCssFilename'] = null; + } + // always check for flash messages and add them if they exist if (Session::hasFlashMessages()){ $flashMessages = Session::getFlashMessages(); diff --git a/src/Controller/CssController/CssController.php b/src/Controller/CssController/CssController.php index 565b54e..b48fbf4 100644 --- a/src/Controller/CssController/CssController.php +++ b/src/Controller/CssController/CssController.php @@ -3,8 +3,8 @@ class CssController extends Controller { public function index() { global $app; - - $customCss = CssModel::load(); + $cssModel = new CssModel($app['db']); + $customCss = $cssModel->getAll(); $vars = [ 'user' => $app['user'], @@ -16,7 +16,8 @@ class CssController extends Controller { } public function serveCustomCss(string $baseFilename){ - $cssModel = new CssModel(); + global $app; + $cssModel = new CssModel($app['db']); $filename = "$baseFilename.css"; $cssRow = $cssModel->getByFilename($filename); @@ -77,7 +78,7 @@ class CssController extends Controller { // Get the data for the selected CSS file $cssId = $_POST['selectCssFile']; - $cssModel = new CssModel(); + $cssModel = new CssModel($app['db']); $cssRow = $cssModel->getById($cssId); // exit if the requested file isn't in the database @@ -182,7 +183,8 @@ class CssController extends Controller { } // Add upload to database - $cssModel = new CssModel(); + global $app; + $cssModel = new CssModel($app['db']); $cssModel->save($safeFilename, $description); // Set success flash message diff --git a/src/Controller/EmojiController/EmojiController.php b/src/Controller/EmojiController/EmojiController.php index 9989f92..3940cc0 100644 --- a/src/Controller/EmojiController/EmojiController.php +++ b/src/Controller/EmojiController/EmojiController.php @@ -3,8 +3,9 @@ // Shows the custom emoji management page public function index(){ global $app; - - $emojiList = EmojiModel::loadAll(); + + $emojiModel = new EmojiModel($app['db']); + $emojiList = $emojiModel->getAll(); $vars = [ 'config' => $app['config'], @@ -34,14 +35,14 @@ exit; } - public function handleAdd(string $emoji, ?string $description=null): void { + private function isValidEmoji(string $emoji){ // Validate 1 visible character in the emoji if (extension_loaded('mbstring')) { // TODO - log a warning if mbstring isn't loaded $charCount = mb_strlen($emoji, 'UTF-8'); if ($charCount !== 1) { // TODO - handle error - return; + return false; } } @@ -50,25 +51,40 @@ if (!preg_match($emojiPattern, $emoji)) { // TODO - handle error - return; + return false; } // emojis should have more bytes than characters $byteCount = strlen($emoji); if ($byteCount <= 1) { // TODO - handle error + return false; + } + + return true; + } + + public function handleAdd(string $emoji, ?string $description=null): void { + global $app; + + if (!$this->isValidEmoji($emoji)){ + // TODO - handle return; } // It looks like an emoji. Let's add it. - EmojiModel::add($emoji, $description); + $emojiModel = new EmojiModel($app['db']); + $emojiList = $emojiModel->add($emoji, $description); } public function handleDelete(): void { + global $app; + $ids = $_POST['delete_emoji_ids']; if (!empty($ids)) { - EmojiModel::delete($ids); + $emojiModel = new EmojiModel($app['db']); + $emojiModel->delete($ids); } } } \ No newline at end of file diff --git a/src/Controller/MoodController/MoodController.php b/src/Controller/MoodController/MoodController.php index 450df86..65b9303 100644 --- a/src/Controller/MoodController/MoodController.php +++ b/src/Controller/MoodController/MoodController.php @@ -2,7 +2,7 @@ class MoodController extends Controller { public function index(){ global $app; - + $view = new MoodView(); $moodPicker = $view->render_mood_picker(self::getEmojisWithLabels(), $app['user']->mood); @@ -17,7 +17,7 @@ public function handlePost(){ global $app; - + if ($_SERVER['REQUEST_METHOD'] === 'POST') { switch ($_POST['action']){ case 'set': @@ -39,7 +39,10 @@ } private static function getEmojisWithLabels(): array { - $customEmoji = EmojiModel::loadAll(); + global $app; + + $emojiModel = new EmojiModel($app['db']); + $customEmoji = $emojiModel->getAll(); if (!empty($customEmoji)){ $custom = []; diff --git a/src/Model/ConfigModel/ConfigModel.php b/src/Model/ConfigModel/ConfigModel.php index e6f0d92..8d76d9f 100644 --- a/src/Model/ConfigModel/ConfigModel.php +++ b/src/Model/ConfigModel/ConfigModel.php @@ -13,15 +13,8 @@ class ConfigModel { public function __construct(private PDO $db) {} - // load config from sqlite database (backward compatibility) - public static function load(): self { - global $db; - $instance = new self($db); - return $instance->loadFromDatabase(); - } - // Instance method that uses injected database - public function loadFromDatabase(): self { + public function get(): self { $init = require APP_ROOT . '/config/init.php'; $c = new self($this->db); $c->baseUrl = ($c->baseUrl === '') ? $init['base_url'] : $c->baseUrl; @@ -53,18 +46,6 @@ class ConfigModel { return $c; } - public function customCssFilename() { - if (empty($this->cssId)) { - return null; - } - - // Fetch filename from css table using cssId - $cssModel = new CssModel(); - $cssRecord = $cssModel->getById($this->cssId); - - return $cssRecord ? $cssRecord['filename'] : null; - } - public function save(): self { $settingsCount = (int) $this->db->query("SELECT COUNT(*) FROM settings")->fetchColumn(); @@ -104,6 +85,6 @@ class ConfigModel { $this->logLevel ]); - return $this->loadFromDatabase(); + return $this->get(); } } diff --git a/src/Model/CssModel/CssModel.php b/src/Model/CssModel/CssModel.php index 7884b06..1bbfe14 100644 --- a/src/Model/CssModel/CssModel.php +++ b/src/Model/CssModel/CssModel.php @@ -1,44 +1,41 @@ prepare("SELECT id, filename, description FROM css ORDER BY filename"); + public function __construct(private PDO $db) {} + + public function getAll(): Array { + $stmt = $this->db->prepare("SELECT id, filename, description FROM css ORDER BY filename"); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } + public function getById(int $id): Array{ - global $db; - $stmt = $db->prepare("SELECT id, filename, description FROM css WHERE id=?"); + $stmt = $this->db->prepare("SELECT id, filename, description FROM css WHERE id=?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } public function getByFilename(string $filename): Array{ - global $db; - $stmt = $db->prepare("SELECT id, filename, description FROM css WHERE filename=?"); + $stmt = $this->db->prepare("SELECT id, filename, description FROM css WHERE filename=?"); $stmt->execute([$filename]); return $stmt->fetch(PDO::FETCH_ASSOC); } public function delete(int $id): bool{ - global $db; - $stmt = $db->prepare("DELETE FROM css WHERE id=?"); + $stmt = $this->db->prepare("DELETE FROM css WHERE id=?"); return $stmt->execute([$id]); } public function save(string $filename, ?string $description = null): void { - global $db; - - $stmt = $db->prepare("SELECT COUNT(id) FROM css WHERE filename = ?"); + $stmt = $this->db->prepare("SELECT COUNT(id) FROM css WHERE filename = ?"); $stmt->execute([$filename]); $fileExists = $stmt->fetchColumn(); if ($fileExists) { - $stmt = $db->prepare("UPDATE css SET description = ? WHERE filename = ?"); + $stmt = $this->db->prepare("UPDATE css SET description = ? WHERE filename = ?"); } else { - $stmt = $db->prepare("INSERT INTO css (filename, description) VALUES (?, ?)"); + $stmt = $this->db->prepare("INSERT INTO css (filename, description) VALUES (?, ?)"); } $stmt->execute([$filename, $description]); diff --git a/src/Model/EmojiModel/EmojiModel.php b/src/Model/EmojiModel/EmojiModel.php index 99b2530..4cde079 100644 --- a/src/Model/EmojiModel/EmojiModel.php +++ b/src/Model/EmojiModel/EmojiModel.php @@ -1,29 +1,25 @@ query("SELECT id, emoji, description FROM emoji"); + public function getAll(): array { + $stmt = $this->db->query("SELECT id, emoji, description FROM emoji"); return $stmt->fetchAll(PDO::FETCH_ASSOC); } // I'm not going to support editing emoji. // It'll just be a delete/readd - public static function add(string $emoji, ?string $description): void{ - global $db; - - $stmt = $db->prepare("INSERT INTO emoji (emoji, description) VALUES (?, ?)"); + public function add(string $emoji, ?string $description): void{ + $stmt = $this->db->prepare("INSERT INTO emoji (emoji, description) VALUES (?, ?)"); $stmt->execute([$emoji, $description]); } - public static function delete(array $idsToDelete): void{ - global $db; - + public function delete(array $idsToDelete): void{ $placeholders = rtrim(str_repeat('?,', count($idsToDelete)), ','); - $stmt = $db->prepare("DELETE FROM emoji WHERE id IN ($placeholders)"); + $stmt = $this->db->prepare("DELETE FROM emoji WHERE id IN ($placeholders)"); $stmt->execute($idsToDelete); } } \ No newline at end of file diff --git a/src/Model/UserModel/UserModel.php b/src/Model/UserModel/UserModel.php index 48b032f..86078ea 100644 --- a/src/Model/UserModel/UserModel.php +++ b/src/Model/UserModel/UserModel.php @@ -8,15 +8,7 @@ class UserModel { public function __construct(private PDO $db) {} - // load user settings from sqlite database (backward compatibility) - public static function load(): self { - global $db; - $instance = new self($db); - return $instance->loadFromDatabase(); - } - - // Instance method that uses injected database - public function loadFromDatabase(): self { + public function get(): self { // There's only ever one user. I'm just leaning into that. $stmt = $this->db->query("SELECT username, display_name, website, mood FROM user WHERE id=1"); $row = $stmt->fetch(PDO::FETCH_ASSOC); @@ -43,7 +35,7 @@ class UserModel { $stmt->execute([$this->username, $this->displayName, $this->website, $this->mood]); - return $this->loadFromDatabase(); + return $this->get(); } // Making this a separate function to avoid diff --git a/templates/main.php b/templates/main.php index 0045384..c98d36d 100644 --- a/templates/main.php +++ b/templates/main.php @@ -2,6 +2,7 @@ + @@ -13,7 +14,7 @@ href="basePath, 'css/default.css')) ?>"> cssId)): ?> + href="basePath, 'css/custom/' . $customCssFilename)) ?>">