get('app.timezone')); return ($timezone !== '' && in_array($timezone, DateTimeZone::listIdentifiers(), true)) ? $timezone : 'UTC'; } function app_now(): string { return gmdate('Y-m-d H:i:s'); } function app_is_prod(): bool { return Base::instance()->get('app.env') === 'prod'; } // ── Fichiers et chemins ───────────────────────────────────────────── function app_ensure_dir(string $path): void { if (!is_dir($path)) { mkdir($path, 0775, true); } } function app_db_path(): string { return app_root() . '/db/app.sqlite'; } function app_logs_dir(): string { return app_root() . '/logs'; } function app_public_media_dir(): string { return app_root() . '/public/uploads/media'; } function app_media_url(string $fileName): string { return rtrim((string) Base::instance()->get('BASE'), '/') . '/uploads/media/' . rawurlencode($fileName); } // ── Texte ─────────────────────────────────────────────────────────── function app_slugify(string $value): string { $slug = Web::instance()->slug(trim($value)); return $slug !== '' ? $slug : 'article'; } function app_unique_slug(string $value, callable $exists): string { $base = app_slugify($value); if (!$exists($base)) { return $base; } for ($i = 2; $i <= 1000; $i++) { $candidate = $base . '-' . $i; if (!$exists($candidate)) { return $candidate; } } throw new RuntimeException('Impossible de générer un slug unique.'); } function app_format_datetime_fr(string $value): string { static $utc, $formatter; $value = trim($value); if ($value === '') { return ''; } try { $utc ??= new DateTimeZone('UTC'); $date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $value, $utc); if (!$date instanceof DateTimeImmutable) { $date = new DateTimeImmutable($value, $utc); } $date = $date->setTimezone(new DateTimeZone(date_default_timezone_get())); if (class_exists('IntlDateFormatter')) { $formatter ??= new IntlDateFormatter( 'fr_FR', IntlDateFormatter::LONG, IntlDateFormatter::SHORT, date_default_timezone_get(), IntlDateFormatter::GREGORIAN, "d MMMM yyyy 'à' HH:mm" ); $formatted = $formatter->format($date); if (is_string($formatted) && $formatted !== '') { return $formatted; } } $months = [ 1 => 'janvier', 2 => 'février', 3 => 'mars', 4 => 'avril', 5 => 'mai', 6 => 'juin', 7 => 'juillet', 8 => 'août', 9 => 'septembre', 10 => 'octobre', 11 => 'novembre', 12 => 'décembre', ]; return sprintf( '%d %s %d à %s', (int) $date->format('j'), $months[(int) $date->format('n')] ?? $date->format('F'), (int) $date->format('Y'), $date->format('H:i') ); } catch (Throwable) { return $value; } }