Ajouter les pages personnalisées au site public

This commit is contained in:
Alexandre NOEL 2026-10-12 10:42:59 +02:00
commit 21ee1bec36
17 changed files with 428 additions and 65 deletions

View file

@ -13,8 +13,8 @@ final class PublicSiteController
if ($path === '/site' || str_starts_with($path, '/site/')) {
return true;
}
return self::usesRoot() &&
in_array(
if (!self::usesRoot()) return false;
if (in_array(
$path,
[
'/',
@ -28,7 +28,9 @@ final class PublicSiteController
'/logo-association',
],
true,
);
)) return true;
return (bool) preg_match('#^/[a-z0-9-]+$#', $path)
&& PublicPageService::findBySlug(trim($path, '/')) !== null;
}
public static function url(string $page = 'home', array $query = []): string
{
@ -43,8 +45,10 @@ final class PublicSiteController
'legal' => $root ? '/mentions-legales' : '/site/mentions-legales',
'privacy' => $root ? '/confidentialite' : '/site/confidentialite',
'logo' => $root ? '/logo-association' : '/site/logo',
'custom' => ($root ? '/' : '/site/page/') . PublicPageService::normalizeSlug((string) ($query['slug'] ?? '')),
default => $root ? '/' : '/site',
};
unset($query['slug']);
return $path . ($query ? '?' . http_build_query($query) : '');
}
public static function dispatch(string $path): void
@ -59,6 +63,10 @@ final class PublicSiteController
self::logo();
return;
}
if (preg_match('#^/site/page/([a-z0-9-]+)$#', $path, $match)) {
self::customPage($match[1]);
return;
}
match ($path) {
'/site', '/site/' => self::home(),
'/site/animaux' => self::animals(),
@ -73,7 +81,7 @@ final class PublicSiteController
}
private static function normalize(string $path): string
{
return match ($path) {
$normalized = match ($path) {
'/' => '/site',
'/animaux' => '/site/animaux',
'/adoption' => '/site/animal',
@ -85,6 +93,11 @@ final class PublicSiteController
'/logo-association' => '/site/logo',
default => $path,
};
if ($normalized === $path && self::usesRoot() && preg_match('#^/([a-z0-9-]+)$#', $path, $match)
&& PublicPageService::findBySlug($match[1]) !== null) {
return '/site/page/' . $match[1];
}
return $normalized;
}
private static function home(): void
{
@ -160,6 +173,20 @@ final class PublicSiteController
'kind' => 'about',
]);
}
private static function customPage(string $slug): void
{
$page = PublicPageService::findBySlug($slug);
if (!$page) {
self::notFound();
return;
}
self::render('public_site_text.php', [
'title' => $page['title'],
'content' => $page['content'],
'kind' => 'custom',
'customPage' => $page,
]);
}
private static function legal(): void
{
self::render('public_site_text.php', [
@ -262,6 +289,7 @@ final class PublicSiteController
extract($vars, EXTR_SKIP);
$settings = AppSettings::all();
$publicSpecies = self::species();
$publicPages = PublicPageService::all(true);
require dirname(__DIR__) . '/Views/public_site_layout.php';
}
private static function notFound(): void

View file

@ -759,6 +759,7 @@ final class SettingsController
'saved' => isset($_GET['saved']),
'error' => (string) ($_GET['error'] ?? ''),
'images' => $images,
'customPages' => PublicPageService::all(),
]);
}
@ -869,22 +870,30 @@ final class SettingsController
'public_site_routing' => $routing,
'public_site_about_enabled' => isset($_POST['public_site_about_enabled']) ? '1' : '0',
];
foreach (
[
'public_site_home_title' => 150,
'public_site_name' => 150,
'public_site_home_text' => 5000,
'public_site_about_title' => 150,
'public_site_about_text' => 10000,
'public_site_donation_title' => 150,
'public_site_donation_text' => 10000,
'public_site_contact_text' => 5000,
'public_site_legal_text' => 15000,
'public_site_privacy_text' => 15000,
]
as $key => $max
) {
$values[$key] = mb_substr(trim((string) ($_POST[$key] ?? '')), 0, $max);
$navigation = json_decode((string) ($_POST['public_site_navigation_order'] ?? '[]'), true);
$navigation = is_array($navigation) ? array_values(array_unique(array_filter($navigation, static function ($item): bool {
if (!is_string($item)) return false;
return in_array($item, ['home','animals','about','donation','contact'], true)
|| (bool) preg_match('/^custom:[a-z0-9-]{1,80}$/', $item);
}))) : [];
$submittedPageSlugs = [];
foreach ((array) ($_POST['pages'] ?? []) as $submittedPage) {
if (!is_array($submittedPage) || !empty($submittedPage['delete'])) continue;
$submittedSlug = PublicPageService::normalizeSlug((string) ($submittedPage['slug'] ?? $submittedPage['title'] ?? ''));
if ($submittedSlug !== '') $submittedPageSlugs[] = $submittedSlug;
}
$navigation = array_values(array_filter($navigation, static function (string $item) use ($submittedPageSlugs): bool {
return !str_starts_with($item, 'custom:') || in_array(substr($item, 7), $submittedPageSlugs, true);
}));
foreach (['home','animals','about','donation','contact'] as $required) {
if (!in_array($required, $navigation, true)) $navigation[] = $required;
}
$values['public_site_navigation_order'] = json_encode($navigation, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
foreach (['public_site_home_title','public_site_name','public_site_about_title','public_site_donation_title'] as $key) {
$values[$key] = mb_substr(trim((string) ($_POST[$key] ?? '')), 0, 150);
}
foreach (['public_site_home_text','public_site_about_text','public_site_donation_text','public_site_contact_text','public_site_legal_text','public_site_privacy_text'] as $key) {
$values[$key] = trim((string) ($_POST[$key] ?? ''));
}
$customCss = trim((string) ($_POST['public_site_custom_css'] ?? ''));
if (strlen($customCss) > 30000 || preg_match('/(?:<\/style|@import|expression\s*\(|javascript\s*:|behavior\s*:|-moz-binding|url\s*\()/i', $customCss)) {
@ -914,9 +923,19 @@ final class SettingsController
}
$values[$key] = $url;
}
AppSettings::save($values, Auth::id());
AuditService::log('public_site_saved', '/settings/public-site/save', 'Configuration du site public modifiée');
header('Location: /settings/public-site?saved=1');
$db = DB::pdo();
try {
$db->beginTransaction();
AppSettings::save($values, Auth::id());
PublicPageService::saveAll((array) ($_POST['pages'] ?? []));
$db->commit();
AuditService::log('public_site_saved', '/settings/public-site/save', 'Configuration du site public modifiée');
header('Location: /settings/public-site?saved=1');
} catch (Throwable $e) {
if ($db->inTransaction()) $db->rollBack();
$message = $e instanceof InvalidArgumentException ? $e->getMessage() : SecurityService::publicError($e);
header('Location: /settings/public-site?error=' . rawurlencode($message));
}
exit();
}
public static function audit(): void