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 <greg@subcultureofone.org> Co-committed-by: Greg Sarjeant <greg@subcultureofone.org>
This commit is contained in:
parent
dc4f60ce2e
commit
832b7b95fa
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -4,7 +4,8 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 = [];
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,41 @@
|
||||
<?php
|
||||
class CssModel {
|
||||
public static function load(): Array {
|
||||
global $db;
|
||||
$stmt = $db->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]);
|
||||
|
@ -1,29 +1,25 @@
|
||||
<?php
|
||||
// welp this model is overkill
|
||||
class EmojiModel{
|
||||
public function __construct(private PDO $db) {}
|
||||
|
||||
// This isn't memory-efficient,
|
||||
// but I think it'll be fine on this app's scales.
|
||||
public static function loadAll(): array {
|
||||
global $db;
|
||||
|
||||
$stmt = $db->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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -2,6 +2,7 @@
|
||||
<?php /** @var ConfigModel $config */ ?>
|
||||
<?php /** @var UserModel $user */ ?>
|
||||
<?php /** @var string $childTemplateFile */ ?>
|
||||
<?php /** @var string $customCssFilename */ ?>
|
||||
<?php /** @var srting $flashSection */ ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -13,7 +14,7 @@
|
||||
href="<?= Util::escape_html(Util::buildRelativeUrl($config->basePath, 'css/default.css')) ?>">
|
||||
<?php if (!empty($config->cssId)): ?>
|
||||
<link rel="stylesheet"
|
||||
href="<?= Util::escape_html(Util::buildRelativeUrl($config->basePath, 'css/custom/' . $config->customCssFilename())) ?>">
|
||||
href="<?= Util::escape_html(Util::buildRelativeUrl($config->basePath, 'css/custom/' . $customCssFilename)) ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
|
Loading…
x
Reference in New Issue
Block a user