-
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Budget;
|
||||
|
||||
use PDO;
|
||||
|
||||
final class Settings
|
||||
{
|
||||
private const DEFAULTS = [
|
||||
'app.name' => 'Neon Ledger',
|
||||
'app.currency_symbol' => '$',
|
||||
'app.timezone' => 'America/New_York',
|
||||
'theme.default' => 'dark',
|
||||
'modules.income' => true,
|
||||
'modules.bills' => true,
|
||||
'modules.calendar' => true,
|
||||
'modules.dead_account' => true,
|
||||
'modules.comparisons' => true,
|
||||
'modules.alerts' => true,
|
||||
'modules.import_export' => true,
|
||||
'dead.income_mode' => 'percent',
|
||||
'dead.income_value' => 0,
|
||||
'dead.transaction_mode' => 'fixed',
|
||||
'dead.transaction_value' => 0,
|
||||
'dead.hide_balance' => true,
|
||||
'alerts.email' => '',
|
||||
'alerts.windows' => [7, 3, 1],
|
||||
'alerts.times' => ['09:00'],
|
||||
'mailgun.api_key' => '',
|
||||
'mailgun.domain' => '',
|
||||
'mailgun.region' => 'us',
|
||||
'mailgun.from' => 'Budget Planner <budget@example.com>',
|
||||
'security.2fa_required' => false,
|
||||
];
|
||||
|
||||
public function __construct(private PDO $pdo)
|
||||
{
|
||||
$this->seed();
|
||||
}
|
||||
|
||||
public function get(string $key, mixed $fallback = null): mixed
|
||||
{
|
||||
$statement = $this->pdo->prepare('SELECT setting_value FROM settings WHERE setting_key = :key');
|
||||
$statement->execute(['key' => $key]);
|
||||
$value = $statement->fetchColumn();
|
||||
if ($value === false) {
|
||||
return self::DEFAULTS[$key] ?? $fallback;
|
||||
}
|
||||
$decoded = json_decode((string) $value, true);
|
||||
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
|
||||
}
|
||||
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
$encoded = json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
if ($encoded === false) {
|
||||
throw new \InvalidArgumentException('Setting value cannot be encoded.');
|
||||
}
|
||||
$sql = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME) === 'mysql'
|
||||
? 'INSERT INTO settings (setting_key, setting_value) VALUES (:key, :value)
|
||||
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value), updated_at = CURRENT_TIMESTAMP'
|
||||
: 'INSERT INTO settings (setting_key, setting_value) VALUES (:key, :value)
|
||||
ON CONFLICT(setting_key) DO UPDATE SET setting_value = excluded.setting_value, updated_at = CURRENT_TIMESTAMP';
|
||||
$statement = $this->pdo->prepare($sql);
|
||||
$statement->execute(['key' => $key, 'value' => $encoded]);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function all(): array
|
||||
{
|
||||
$settings = self::DEFAULTS;
|
||||
foreach ($this->pdo->query('SELECT setting_key, setting_value FROM settings')->fetchAll() as $row) {
|
||||
$decoded = json_decode((string) $row['setting_value'], true);
|
||||
$settings[$row['setting_key']] = json_last_error() === JSON_ERROR_NONE ? $decoded : $row['setting_value'];
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
public function module(string $name): bool
|
||||
{
|
||||
return (bool) $this->get('modules.' . $name, true);
|
||||
}
|
||||
|
||||
private function seed(): void
|
||||
{
|
||||
$count = (int) $this->pdo->query('SELECT COUNT(*) FROM settings')->fetchColumn();
|
||||
if ($count > 0) {
|
||||
return;
|
||||
}
|
||||
foreach (self::DEFAULTS as $key => $value) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user