Initial MVC refactor

This commit is contained in:
Greg Sarjeant 2025-06-02 16:40:31 -04:00
parent 7a85c7f9dd
commit cacbf85283
9 changed files with 118 additions and 67 deletions

View File

@ -1,5 +1,4 @@
<?php
#require_once __DIR__ . '/../bootstrap.php';
define('APP_ROOT', dirname(dirname(__FILE__)));
@ -33,10 +32,7 @@ foreach (recursive_glob('*.php', SRC_DIR) as $file) {
}
confirm_setup();
$isLoggedIn = isset($_SESSION['user_id']);
$config = Config::load();
$user = User::load();
// Get request data
$method = $_SERVER['REQUEST_METHOD'];
@ -80,21 +76,9 @@ function route($pattern, $callback, $methods = ['GET']) {
// Set content type
header('Content-Type: text/html; charset=utf-8');
echo "Path: " . $path;
// routes
route('', function() use ($isLoggedIn, $config, $user) {
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = $config->itemsPerPage;
$offset = ($page - 1) * $limit;
$ticks = iterator_to_array(stream_ticks($limit, $offset));
$vars = [
'isLoggedIn' => $isLoggedIn,
'config' => $config,
'user' => $user,
'ticks' => $ticks,
];
echo render_template(TEMPLATES_DIR . "/home.php", $vars);
route('', function(){
$hc = new HomeController();
echo $hc->render();
});

View File

@ -0,0 +1,77 @@
<?php
class HomeController{
private function stream_ticks(int $limit, int $offset = 0): Generator {
$tick_files = glob(TICKS_DIR . '/*/*/*.txt');
usort($tick_files, fn($a, $b) => strcmp($b, $a)); // sort filenames in reverse chronological order
$count = 0;
foreach ($tick_files as $file) {
// read all the ticks from the current file and reverse the order
// so the most recent ones are first
//
// each file is a single day, so we never hold more than
// one day's ticks in memory
$lines = array_reverse(
file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
);
// split the path to the current file into the date components
$pathParts = explode('/', str_replace('\\', '/', $file));
// assign the different components to the appropriate part of the date
$year = $pathParts[count($pathParts) - 3];
$month = $pathParts[count($pathParts) - 2];
$day = pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME);
foreach ($lines as $line) {
// just keep skipping ticks until we get to the starting point
if ($offset > 0) {
$offset--;
continue;
}
// Ticks are pipe-delimited: timestamp|text
// But just in case a tick contains a pipe, only split on the first one that occurs
$tickParts = explode('|', $line, 2);
$time = $tickParts[0];
$tick = $tickParts[1];
// Build the timestamp from the date and time
// Ticks are always stored in UTC
$timestampUTC = "$year-$month-$day $time";
yield [
'timestamp' => $timestampUTC,
'tick' => $tick,
];
if (++$count >= $limit) {
return;
}
}
}
}
public function render(){
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$isLoggedIn = isset($_SESSION['user_id']);
$config = Config::load();
$user = User::load();
$limit = $config->itemsPerPage;
$offset = ($page - 1) * $limit;
$ticks = iterator_to_array(stream_ticks($limit, $offset));
$view = new HomeView();
$tickList = $view->renderTicksSection($config->siteDescription, $ticks, $page, $limit);
$vars = [
'isLoggedIn' => $isLoggedIn,
'config' => $config,
'user' => $user,
'tickList' => $tickList,
];
echo render_template(TEMPLATES_DIR . "/home.php", $vars);
}
}

View File

@ -1,10 +1,4 @@
<?php
#require_once __DIR__ . '/../bootstrap.php';
#confirm_setup();
// Made this a class so it could be more obvious where config settings are coming from.
// Felt too much like magic constants in other files before.
class Config {
// properties and default values
public string $siteTitle = 'My tkr';
@ -39,9 +33,4 @@ class Config {
return self::load();
}
// I'm making this
public function setPassword(){
}
}

31
src/View/Home/Home.php Normal file
View File

@ -0,0 +1,31 @@
<?php
class HomeView {
public function renderTicksSection(string $siteDescription, array $ticks, int $page, int $limit){
ob_start();
?>
<section id="ticks" class="home-ticks">
<div class="home-ticks-header">
<h2><?= $siteDescription ?></h2>
</div>
<div class="home-ticks-list">
<?php foreach ($ticks as $tick): ?>
<article class="tick">
<div class="tick-time"><?= htmlspecialchars(relative_time($tick['timestamp'])) ?></div>
<span class="tick-text"><?= escape_and_linkify($tick['tick']) ?></span>
</article>
<?php endforeach; ?>
</div>
<div class="home-ticks-pagination">
<?php if ($page > 1): ?>
<a href="?page=<?= $page - 1 ?>">&laquo; Newer</a>
<?php endif; ?>
<?php if (count($ticks) === $limit): ?>
<a href="?page=<?= $page + 1 ?>">Older &raquo;</a>
<?php endif; ?>
</div>
</section>
<?php return ob_get_clean();
}
}

View File

@ -1,17 +1,8 @@
<?php
#require_once __DIR__ . '/../bootstrap.php';
#require_once CLASSES_DIR . '/Config.php';
#require_once CLASSES_DIR . '/User.php';
#require LIB_DIR . '/emoji.php';
function save_mood(string $mood): void {
$config = Config::load();
$user = User::load();
//$db = get_db();
//$stmt = $db->prepare("UPDATE user SET mood=? WHERE username=?");
//$stmt->execute([$mood, $_SESSION['username']]);
$user->mood = $mood;
$user = $user->save();

View File

@ -1,5 +1,4 @@
<?php
#require_once __DIR__ . '/../bootstrap.php';
function save_tick(string $tick): void {
// build the tick path and filename from the current time
@ -24,6 +23,8 @@ function save_tick(string $tick): void {
file_put_contents($filename, $content, FILE_APPEND);
}
// TODO - move this into a view along with
// the code that builds the tick list.
function stream_ticks(int $limit, int $offset = 0): Generator {
$tick_files = glob(TICKS_DIR . '/*/*/*.txt');
usort($tick_files, fn($a, $b) => strcmp($b, $a)); // sort filenames in reverse chronological order
@ -46,9 +47,6 @@ function stream_ticks(int $limit, int $offset = 0): Generator {
$year = $pathParts[count($pathParts) - 3];
$month = $pathParts[count($pathParts) - 2];
$day = pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME);
// $date = $pathParts[count($pathParts) - 3] . '-' .
// $pathParts[count($pathParts) - 2] . '-' .
// pathinfo($pathParts[count($pathParts) - 1], PATHINFO_FILENAME);
foreach ($lines as $line) {
// just keep skipping ticks until we get to the starting point

View File

@ -38,6 +38,7 @@ function relative_time(string $tickTime): string {
}
return $diff->s . ' second' . ($diff->s != 1 ? 's' : '') . ' ago';
}
function verify_data_dir(string $dir, bool $allow_create = false): void {
if (!is_dir($dir)) {
if ($allow_create) {
@ -117,9 +118,9 @@ function get_db(): PDO {
return $db;
}
// TODO - Maybe this is the sort of thing that would be good
// in a Controller base class.
function render_template(string $templateFile, array $vars = []): string {
#$templatePath = TEMPLATES_DIR . '/' . ltrim($templateFile, '/');
if (!file_exists($templateFile)) {
throw new RuntimeException("Template not found: $templatePath");
}

View File

@ -1,7 +1,7 @@
<?php /** @var bool $isLoggedIn */ ?>
<?php /** @var Config $config */ ?>
<?php /** @var User $user */ ?>
<?php /** @var array $ticks */ ?>
<?php /** @var string $tickList */ ?>
<!DOCTYPE html>
<html>
@ -48,27 +48,7 @@
</div>
<?php endif; ?>
</section>
<section id="ticks" class="home-ticks">
<div class="home-ticks-header">
<h2><?= $config->siteDescription ?></h2>
</div>
<div class="home-ticks-list">
<?php foreach ($ticks as $tick): ?>
<article class="tick">
<div class="tick-time"><?= htmlspecialchars(relative_time($tick['timestamp'])) ?></div>
<span class="tick-text"><?= escape_and_linkify($tick['tick']) ?></span>
</article>
<?php endforeach; ?>
</div>
<div class="home-ticks-pagination">
<?php if ($page > 1): ?>
<a href="?page=<?= $page - 1 ?>">&laquo; Newer</a>
<?php endif; ?>
<?php if (count($ticks) === $limit): ?>
<a href="?page=<?= $page + 1 ?>">Older &raquo;</a>
<?php endif; ?>
</div>
</section>
<?php echo $tickList ?>
</div>
</body>
</html>