Clean code

This commit is contained in:
julien
2026-03-27 22:30:10 +01:00
parent 68c547ddcb
commit 7757628a94
29 changed files with 164 additions and 268 deletions

View File

@@ -56,15 +56,13 @@ function app_media_url(string $fileName): string
// ── 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);
$base = Web::instance()->slug(trim($value));
if ($base === '') {
$base = 'article';
}
if (!$exists($base)) {
return $base;
}
@@ -97,35 +95,18 @@ function app_format_datetime_fr(string $value): string
$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')
$formatter ??= new IntlDateFormatter(
'fr_FR',
IntlDateFormatter::LONG,
IntlDateFormatter::SHORT,
date_default_timezone_get(),
IntlDateFormatter::GREGORIAN,
"d MMMM yyyy 'à' HH:mm"
);
$formatted = $formatter->format($date);
return is_string($formatted) && $formatted !== '' ? $formatted : $value;
} catch (Throwable) {
return $value;
}

View File

@@ -2,16 +2,6 @@
declare(strict_types=1);
function app_error_meta(int $code): array
{
return match ($code) {
400 => ['title' => 'Requête invalide', 'message' => 'La requête envoyée est invalide.'],
403 => ['title' => 'Accès refusé', 'message' => 'Tu n\u2019as pas accès à cette ressource.'],
404 => ['title' => 'Page introuvable', 'message' => 'La page demandée est introuvable.'],
default => ['title' => 'Erreur serveur', 'message' => 'Une erreur est survenue.'],
};
}
function app_bootstrap_logging(): void
{
$dir = rtrim((string) Base::instance()->get('LOGS'), '/\\') . DIRECTORY_SEPARATOR;
@@ -22,78 +12,27 @@ function app_bootstrap_logging(): void
error_reporting(E_ALL);
}
function app_request_summary(): string
function app_error_meta(int $code): array
{
$f3 = Base::instance();
return sprintf(
'request=%s %s ip=%s',
(string) ($f3->get('VERB') ?? 'CLI'),
(string) ($f3->get('URI') ?? '/'),
(string) ($f3->get('IP') ?? '0.0.0.0')
);
}
function app_write_log(string $fileName, string $line): void
{
(new Log($fileName))->write($line);
}
function app_log_error(int $code, string $status, string $text, ?Throwable $exception = null): void
{
if ($code === 404) {
return;
}
$level = $code >= 500 ? 'error' : ($code >= 400 ? 'warning' : 'info');
$parts = [
sprintf('level=%s code=%d status="%s"', $level, $code, $status),
app_request_summary(),
];
if ($text !== '') {
$parts[] = 'message="' . str_replace(["\n", '"'], ['\\n', '\\"'], $text) . '"';
}
if ($exception !== null) {
$parts[] = sprintf('exception="%s" file="%s:%d"', $exception::class, $exception->getFile(), $exception->getLine());
}
app_write_log('app.log', implode(' | ', $parts));
}
function app_render_error_json(int $code): void
{
$f3 = Base::instance();
$meta = app_error_meta($code);
while (ob_get_level() > 0) {
ob_end_clean();
}
$f3->status($code);
$f3->expire(0);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(
['error' => ['code' => $code, 'title' => $meta['title'], 'message' => $meta['message']]],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
return match ($code) {
400 => ['title' => 'Requête invalide', 'message' => 'La requête envoyée est invalide.'],
403 => ['title' => 'Accès refusé', 'message' => 'Tu n\u2019as pas accès à cette ressource.'],
404 => ['title' => 'Page introuvable', 'message' => 'La page demandée est introuvable.'],
default => ['title' => 'Erreur serveur', 'message' => 'Une erreur est survenue.'],
};
}
function app_render_error_fallback(int $code): void
{
$f3 = Base::instance();
$meta = app_error_meta($code);
$base = rtrim((string) $f3->get('BASE'), '/');
$base = rtrim((string) Base::instance()->get('BASE'), '/');
while (ob_get_level() > 0) {
ob_end_clean();
}
$f3->status($code);
$f3->expire(0);
if (!headers_sent()) {
http_response_code($code);
header('Content-Type: text/html; charset=UTF-8');
header('Cache-Control: no-cache, no-store, must-revalidate');
}
@@ -107,41 +46,28 @@ function app_render_error_fallback(int $code): void
function app_bootstrap_errors(Base $f3): void
{
if (app_is_prod()) {
register_shutdown_function(function (): void {
$error = error_get_last();
if ($error === null) {
return;
}
$fatalTypes = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR];
if (!in_array($error['type'] ?? 0, $fatalTypes, true)) {
return;
}
app_render_error_fallback(500);
});
// En dev, ne pas poser ONERROR : le handler par défaut de F3
// affiche la stack trace complète quand DEBUG > 0.
if (!app_is_prod()) {
return;
}
register_shutdown_function(function (): void {
$error = error_get_last();
if ($error === null) {
return;
}
$fatalTypes = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR];
if (!in_array($error['type'] ?? 0, $fatalTypes, true)) {
return;
}
app_render_error_fallback(500);
});
$f3->set('ONERROR', function (Base $f3): void {
$code = (int) ($f3->get('ERROR.code') ?? 500);
$status = (string) ($f3->get('ERROR.status') ?? 'Internal Server Error');
$text = (string) ($f3->get('ERROR.text') ?? '');
if (!app_is_prod() && (int) $f3->get('DEBUG') > 0) {
$f3->status($code > 0 ? $code : 500);
echo $text;
return;
}
$code = $code > 0 ? $code : 500;
app_log_error($code, $status, $text);
if ($f3->get('AJAX')) {
app_render_error_json($code);
return;
}
$code = max((int) ($f3->get('ERROR.code') ?? 500), 1);
$f3->expire(0);
$f3->status($code);
@@ -154,8 +80,7 @@ function app_bootstrap_errors(Base $f3): void
try {
echo Template::instance()->render('errors/error.html');
} catch (Throwable $exception) {
app_log_error(500, 'Internal Server Error', 'Error template rendering failed.', $exception);
} catch (Throwable) {
app_render_error_fallback($code);
}
});