Publier Globinours 1.0.0-rc.3

This commit is contained in:
Alexandre NOEL 2026-09-03 12:39:15 +02:00
commit 9a2b4068da
325 changed files with 38230 additions and 20 deletions

View file

@ -0,0 +1,272 @@
<?php
declare(strict_types=1);
final class PublicSiteController
{
public static function usesRoot(): bool
{
return AppSettings::get('public_site_routing') === 'root';
}
public static function handles(string $path): bool
{
if ($path === '/site' || str_starts_with($path, '/site/')) {
return true;
}
return self::usesRoot() &&
in_array(
$path,
[
'/',
'/animaux',
'/adoption',
'/presentation',
'/dons',
'/contact',
'/mentions-legales',
'/confidentialite',
'/logo-association',
],
true,
);
}
public static function url(string $page = 'home', array $query = []): string
{
$root = self::usesRoot();
$path = match ($page) {
'home' => $root ? '/' : '/site',
'animals' => $root ? '/animaux' : '/site/animaux',
'animal' => $root ? '/adoption' : '/site/animal',
'about' => $root ? '/presentation' : '/site/presentation',
'donation' => $root ? '/dons' : '/site/dons',
'contact' => $root ? '/contact' : '/site/contact',
'legal' => $root ? '/mentions-legales' : '/site/mentions-legales',
'privacy' => $root ? '/confidentialite' : '/site/confidentialite',
'logo' => $root ? '/logo-association' : '/site/logo',
default => $root ? '/' : '/site',
};
return $path . ($query ? '?' . http_build_query($query) : '');
}
public static function dispatch(string $path): void
{
$path = self::normalize($path);
if (AppSettings::get('public_site_enabled') !== '1') {
http_response_code(404);
self::render('public_site_unavailable.php', ['title' => t('public_site.unavailable')]);
return;
}
if ($path === '/site/logo') {
self::logo();
return;
}
match ($path) {
'/site', '/site/' => self::home(),
'/site/animaux' => self::animals(),
'/site/animal' => self::animal(),
'/site/dons' => self::donation(),
'/site/contact' => self::contact(),
'/site/presentation' => self::about(),
'/site/mentions-legales' => self::legal(),
'/site/confidentialite' => self::privacy(),
default => self::notFound(),
};
}
private static function normalize(string $path): string
{
return match ($path) {
'/' => '/site',
'/animaux' => '/site/animaux',
'/adoption' => '/site/animal',
'/presentation' => '/site/presentation',
'/dons' => '/site/dons',
'/contact' => '/site/contact',
'/mentions-legales' => '/site/mentions-legales',
'/confidentialite' => '/site/confidentialite',
'/logo-association' => '/site/logo',
default => $path,
};
}
private static function home(): void
{
$db = DB::pdo();
$animals = self::animalQuery('', 8);
$counts = $db
->query(
"SELECT species,COUNT(*) count FROM animals WHERE website_published=1 AND adoption_availability='available' AND archived_at IS NULL AND deleted_at IS NULL AND status NOT IN ('adopte','decede') GROUP BY species ORDER BY species",
)
->fetchAll(PDO::FETCH_ASSOC);
self::render('public_site_home.php', [
'title' => AppSettings::get('public_site_home_title'),
'animals' => $animals,
'speciesCounts' => $counts,
]);
}
private static function animals(): void
{
$species = SpeciesService::normalize((string) ($_GET['espece'] ?? ''));
if ($species !== '' && !SpeciesService::exists($species, false)) {
$species = '';
}
self::render('public_site_animals.php', [
'title' => t('public_site.animals'),
'animals' => self::animalQuery($species, 200),
'selectedSpecies' => $species,
'publicSpecies' => self::species(),
]);
}
private static function animal(): void
{
$id = (int) ($_GET['id'] ?? 0);
$s = DB::pdo()->prepare(
"SELECT a.*,s.name species_name,s.icon species_icon,(SELECT filename FROM animal_photos p WHERE p.animal_id=a.id AND p.is_public=1 ORDER BY p.is_primary DESC,p.id DESC LIMIT 1) primary_photo FROM animals a LEFT JOIN ref_species s ON s.code=a.species WHERE a.id=? AND a.website_published=1 AND a.adoption_availability='available' AND a.archived_at IS NULL AND a.deleted_at IS NULL AND a.status NOT IN ('adopte','decede')",
);
$s->execute([$id]);
$animal = $s->fetch(PDO::FETCH_ASSOC);
if (!$animal) {
self::notFound();
return;
}
$p = DB::pdo()->prepare(
'SELECT filename,caption FROM animal_photos WHERE animal_id=? AND is_public=1 ORDER BY is_primary DESC,id DESC',
);
$p->execute([$id]);
self::render('public_site_animal.php', [
'title' => $animal['name'],
'animal' => $animal,
'photos' => $p->fetchAll(PDO::FETCH_ASSOC),
]);
}
private static function donation(): void
{
self::render('public_site_text.php', [
'title' => AppSettings::get('public_site_donation_title'),
'content' => AppSettings::get('public_site_donation_text'),
'kind' => 'donation',
]);
}
private static function contact(): void
{
self::render('public_site_contact.php', ['title' => t('public_site.contact')]);
}
private static function about(): void
{
if (AppSettings::get('public_site_about_enabled') !== '1') {
self::notFound();
return;
}
self::render('public_site_text.php', [
'title' => AppSettings::get('public_site_about_title'),
'content' => AppSettings::get('public_site_about_text'),
'kind' => 'about',
]);
}
private static function legal(): void
{
self::render('public_site_text.php', [
'title' => t('public_site.legal'),
'content' => self::legalText(),
'kind' => 'legal',
]);
}
private static function privacy(): void
{
self::render('public_site_text.php', [
'title' => t('public_site.privacy'),
'content' => self::privacyText(),
'kind' => 'privacy',
]);
}
public static function legalText(?array $settings = null): string
{
$settings ??= AppSettings::all();
$custom = trim((string) ($settings['public_site_legal_text'] ?? ''));
if ($custom !== '') {
return $custom;
}
$address =
implode(
', ',
array_filter([
$settings['association_address'] ?? '',
trim(($settings['association_postal_code'] ?? '') . ' ' . ($settings['association_city'] ?? '')),
]),
) ?:
t('public_site.to_complete');
return t('public_site.default_legal', [
'association' => $settings['association_name'] ?: t('public_site.to_complete'),
'address' => $address,
'email' => $settings['association_email'] ?: t('public_site.to_complete'),
'rna' => $settings['association_rna'] ?: t('public_site.to_complete'),
'siret' => $settings['association_siret'] ?: t('public_site.to_complete'),
]);
}
public static function privacyText(?array $settings = null): string
{
$settings ??= AppSettings::all();
$custom = trim((string) ($settings['public_site_privacy_text'] ?? ''));
if ($custom !== '') {
return $custom;
}
$address =
implode(
', ',
array_filter([
$settings['association_address'] ?? '',
trim(($settings['association_postal_code'] ?? '') . ' ' . ($settings['association_city'] ?? '')),
]),
) ?:
t('public_site.to_complete');
return t('public_site.default_privacy', [
'association' => $settings['association_name'] ?: t('public_site.to_complete'),
'address' => $address,
'email' => $settings['association_email'] ?: t('public_site.to_complete'),
]);
}
private static function logo(): void
{
$path = AssociationBrand::path();
if (!$path) {
http_response_code(404);
return;
}
$mime = new finfo(FILEINFO_MIME_TYPE)->file($path) ?: 'application/octet-stream';
header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($path));
header('Cache-Control: public,max-age=3600');
readfile($path);
}
private static function animalQuery(string $species, int $limit): array
{
$sql =
"SELECT a.id,a.name,a.species,a.sex,a.birth_date,a.birth_is_estimated,a.birth_estimated_months,a.breed,a.color,a.sterilization_status,a.compatibility_dogs,a.compatibility_cats,a.compatibility_children,a.house_trained,a.website_description,s.name species_name,s.icon species_icon,(SELECT filename FROM animal_photos p WHERE p.animal_id=a.id AND p.is_public=1 ORDER BY p.is_primary DESC,p.id DESC LIMIT 1) primary_photo FROM animals a LEFT JOIN ref_species s ON s.code=a.species WHERE a.website_published=1 AND a.adoption_availability='available' AND a.archived_at IS NULL AND a.deleted_at IS NULL AND a.status NOT IN ('adopte','decede')";
$params = [];
if ($species !== '') {
$sql .= ' AND a.species=:species';
$params[':species'] = $species;
}
$sql .= ' ORDER BY a.updated_at DESC,a.name COLLATE NOCASE LIMIT ' . max(1, min(500, $limit));
$s = DB::pdo()->prepare($sql);
$s->execute($params);
return $s->fetchAll(PDO::FETCH_ASSOC);
}
private static function species(): array
{
return DB::pdo()
->query(
"SELECT s.code,s.name,s.icon,COUNT(a.id) count FROM ref_species s JOIN animals a ON a.species=s.code AND a.website_published=1 AND a.adoption_availability='available' AND a.archived_at IS NULL AND a.deleted_at IS NULL AND a.status NOT IN ('adopte','decede') GROUP BY s.id ORDER BY s.sort_order,s.name COLLATE NOCASE",
)
->fetchAll(PDO::FETCH_ASSOC);
}
private static function render(string $view, array $vars = []): void
{
extract($vars, EXTR_SKIP);
$settings = AppSettings::all();
$publicSpecies = self::species();
require dirname(__DIR__) . '/Views/public_site_layout.php';
}
private static function notFound(): void
{
http_response_code(404);
self::render('public_site_unavailable.php', ['title' => t('public_site.not_found')]);
}
}