Moves imgration flag to DB with fallback to file

main
Yasen Pramatarov 2025-09-25 11:50:29 +03:00
parent a77cf5b328
commit 49e147c5b5
4 changed files with 116 additions and 1 deletions

View File

@ -4,15 +4,40 @@ namespace App\Core;
class Maintenance
{
public const FLAG_PATH = __DIR__ . '/../../storage/maintenance.flag';
// Keep it simple: store the flag within the app directory
public const FLAG_PATH = __DIR__ . '/../../app/.maintenance.flag';
public static function isEnabled(): bool
{
if (getenv('JILO_MAINTENANCE') === '1') {
return true;
}
// Prefer DB settings if available in the current request
if (isset($GLOBALS['db'])) {
try {
require_once __DIR__ . '/Settings.php';
$settings = new Settings($GLOBALS['db']);
return $settings->get('maintenance_enabled', '0') === '1';
} catch (\Throwable $e) {
// fall back to file flag
}
}
return file_exists(self::FLAG_PATH);
}
public static function enable(string $message = ''): bool
{
if (isset($GLOBALS['db'])) {
try {
require_once __DIR__ . '/Settings.php';
$settings = new Settings($GLOBALS['db']);
$ok1 = $settings->set('maintenance_enabled', '1');
$ok2 = $settings->set('maintenance_message', $message);
return $ok1 && $ok2;
} catch (\Throwable $e) {
// fall back to file flag
}
}
$dir = dirname(self::FLAG_PATH);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
@ -23,6 +48,17 @@ class Maintenance
public static function disable(): bool
{
if (isset($GLOBALS['db'])) {
try {
require_once __DIR__ . '/Settings.php';
$settings = new Settings($GLOBALS['db']);
$ok1 = $settings->set('maintenance_enabled', '0');
// keep last message for reference, optional to clear
return $ok1;
} catch (\Throwable $e) {
// fall back to file flag
}
}
if (file_exists(self::FLAG_PATH)) {
return unlink(self::FLAG_PATH);
}
@ -34,6 +70,19 @@ class Maintenance
if (!self::isEnabled()) {
return '';
}
$envMsg = getenv('JILO_MAINTENANCE_MESSAGE');
if ($envMsg) {
return trim($envMsg);
}
if (isset($GLOBALS['db'])) {
try {
require_once __DIR__ . '/Settings.php';
$settings = new Settings($GLOBALS['db']);
return (string)$settings->get('maintenance_message', '');
} catch (\Throwable $e) {
// ignore and fall back to file flag
}
}
$msg = @file_get_contents(self::FLAG_PATH);
return is_string($msg) ? trim($msg) : '';
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Core;
use PDO;
use Exception;
class Settings
{
private PDO $pdo;
public function __construct($db)
{
if ($db instanceof PDO) {
$this->pdo = $db;
} elseif (is_object($db) && method_exists($db, 'getConnection')) {
$pdo = $db->getConnection();
if (!$pdo instanceof PDO) {
throw new Exception('Settings: database wrapper did not return PDO');
}
$this->pdo = $pdo;
} else {
$type = is_object($db) ? get_class($db) : gettype($db);
throw new Exception("Settings: unsupported database type: {$type}");
}
$this->ensureTable();
}
private function ensureTable(): void
{
$driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver === 'sqlite') {
$sql = "CREATE TABLE IF NOT EXISTS settings (\n `key` TEXT PRIMARY KEY,\n `value` TEXT,\n `updated_at` TEXT NOT NULL\n )";
} else {
$sql = "CREATE TABLE IF NOT EXISTS settings (\n `key` VARCHAR(191) NOT NULL PRIMARY KEY,\n `value` TEXT NULL,\n `updated_at` DATETIME NOT NULL\n ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
}
$this->pdo->exec($sql);
}
public function get(string $key, $default = null)
{
$stmt = $this->pdo->prepare('SELECT `value` FROM settings WHERE `key` = :k');
$stmt->execute([':k' => $key]);
$val = $stmt->fetchColumn();
if ($val === false) return $default;
return $val;
}
public function set(string $key, $value): bool
{
$stmt = $this->pdo->prepare('REPLACE INTO settings (`key`, `value`, `updated_at`) VALUES (:k, :v, NOW())');
return (bool)$stmt->execute([':k' => $key, ':v' => $value]);
}
}

View File

@ -12,7 +12,12 @@
</div>
<div class="card-body">
<p class="lead">The site is temporarily unavailable due to maintenance.</p>
<?php $mm = \App\Core\Maintenance::getMessage(); ?>
<?php if ($mm): ?>
<p class="mb-0"><em><?= htmlspecialchars($mm) ?></em></p>
<?php else: ?>
<p class="text-muted">Please try again later.</p>
<?php endif; ?>
</div>
</div>
</div>

View File

@ -49,6 +49,13 @@ php scripts/maintenance.php off
php scripts/maintenance.php status
```
Notes:
- The maintenance flag is stored at `app/.maintenance.flag`.
- You can also control maintenance via environment variables (useful when the filesystem is read-only):
- `JILO_MAINTENANCE=1` enables maintenance mode
- `JILO_MAINTENANCE_MESSAGE="Your message"` sets the banner message
## Authoring new migrations
1. Create a new SQL file in `doc/database/migrations/`, e.g.: