Refine public documentation and code comments

This commit is contained in:
Alexandre NOEL 2026-09-04 13:37:22 +02:00
commit 0a482afe9d
16 changed files with 195 additions and 628 deletions

View file

@ -679,7 +679,7 @@ trait AnimalBrowseActions
$stmt->execute([':id' => $id]);
$prevWeight = $stmt->fetchColumn();
// PHOTOS : on récupère TOUT (public + privé)
// Charge les photos publiques et privées pour la fiche interne.
$stmt = $db->prepare('
SELECT id, filename, is_primary, is_public, caption, care_round_id, created_at
FROM animal_photos

View file

@ -248,7 +248,7 @@ trait AnimalMedicalActions
}
$vetName = $vetContact['name'] ?? null;
// 1️⃣ Insertion note médicale
// Enregistre la note médicale avant ses éventuelles pièces jointes.
$stmt = $db->prepare('
INSERT INTO medical_notes
(animal_id, kind, reason, symptoms, exam, diagnosis, plan, temperature_c, weight_kg, clinic_id, vet_name, clinic_contact_id, vet_contact_id, created_by, created_at)
@ -274,7 +274,7 @@ trait AnimalMedicalActions
':created' => self::now(),
]);
// 👉 RÉCUPÉRATION ID NOTE
// Identifiant utilisé pour rattacher les photos à la note.
$medicalNoteId = $db->lastInsertId();
if ((int) ($_POST['tariff_id'] ?? 0) > 0) {
PricingService::record(
@ -287,9 +287,7 @@ trait AnimalMedicalActions
);
}
// ==========================
// 2️⃣ Upload photos médicales
// ==========================
// Enregistre les photos médicales associées.
if (!empty($_FILES['medical_photos']['name'][0])) {
$uploadDir = PrivateMediaService::medicalDir($animalId);
@ -337,7 +335,7 @@ trait AnimalMedicalActions
}
}
// 3️⃣ Poids → measurements (graph)
// Ajoute le poids aux mesures utilisées par le graphique.
if ($weight !== '' && is_numeric($weight)) {
$db->prepare(
"
@ -352,10 +350,10 @@ trait AnimalMedicalActions
]);
}
// 4️⃣ Historique
// Ajoute l'intervention à l'historique de l'animal.
self::logHistory($animalId, 'medical', 'Note médicale ajoutée', $reason ?: null);
// 5️⃣ Touch animal
// Actualise la date de modification de la fiche.
if ($markSterilized) {
$db->prepare(
"UPDATE animals SET sterilized=1,sterilization_status='yes',sterilization_date=COALESCE(sterilization_date,date(:date)),sterilization_vet_contact_id=COALESCE(:vet,sterilization_vet_contact_id),sterilization_clinic_contact_id=COALESCE(:clinic,sterilization_clinic_contact_id) WHERE id=:id",

View file

@ -141,7 +141,7 @@ trait AnimalPhotoActions
continue;
}
// RÈGLE : jamais une privée en principale
// Une photo privée ne peut pas devenir la photo principale.
$isPrimary = !$hasPrimary && $isPublic === 1 ? 1 : 0;
if ($isPrimary === 1) {
$hasPrimary = true;
@ -221,7 +221,7 @@ trait AnimalPhotoActions
throw $e;
}
// Historique si tu veux
// Conserve la suppression dans l'historique de la fiche.
if (method_exists(__CLASS__, 'logHistory')) {
self::logHistory($animalId, 'photo', 'Photo principale modifiée');
}
@ -274,7 +274,7 @@ trait AnimalPhotoActions
@unlink($path);
}
// Si on a supprimé la principale, on met la plus récente restante en principale
// Remplace une photo principale supprimée par la plus récente encore disponible.
if ($wasPrimary) {
$pid = $db
->query('SELECT id FROM animal_photos WHERE animal_id=' . (int) $animalId . ' ORDER BY id DESC LIMIT 1')

View file

@ -204,7 +204,7 @@ trait AnimalRecordActions
'free_cat_captured_at' => '',
'free_cat_released_at' => '',
'free_cat_tracking_status' => 'present',
// adapte si tu as fiv/felv en colonnes
// Normalise les statuts FIV et FeLV enregistrés sur la fiche.
'fiv' => '',
'felv' => '',
];
@ -486,7 +486,7 @@ trait AnimalRecordActions
$birth_estimated_months = null;
}
// FIV/FELV (selon ton stockage actuel)
// Statuts FIV et FeLV enregistrés sur la fiche.
$fiv = array_key_exists('fiv', $_POST) ? (isset($_POST['fiv']) ? 1 : 0) : null;
$felv = array_key_exists('felv', $_POST) ? (isset($_POST['felv']) ? 1 : 0) : null;
@ -514,7 +514,7 @@ trait AnimalRecordActions
$birth_date = $birth_date === '' ? null : $birth_date;
$intake_date = $intake_date === '' ? null : $intake_date;
// Code interne : auto si vide (et idéalement readonly en edit)
// Génère le code interne lorsqu'il est absent.
$internal_code = trim((string) ($_POST['internal_code'] ?? ''));
if ($internal_code === '') {
$internal_code = self::nextInternalCode($name);
@ -528,7 +528,7 @@ trait AnimalRecordActions
$quarantine_until = date('Y-m-d', $ts + AppSettings::int('quarantine_days', 1, 90) * 86400);
}
} else {
// si pas en quarantaine, on vide la sortie (optionnel, mais logique)
// La date de sortie n'a de sens que pour un animal en quarantaine.
$quarantine_until = null;
}
@ -575,7 +575,7 @@ trait AnimalRecordActions
);
$depositorId = $depositor ? (int) $depositor['id'] : null;
// Pour l’instant, tu bloques le lieu actuel
// Le lieu actuel est conservé lorsque la fiche archivée est corrigée.
if ($isArchivedCorrection) {
$currentAddress = (string) ($old['current_address'] ?? '');
}
@ -758,9 +758,7 @@ trait AnimalRecordActions
}
if ($old) {
// Les nouvelles valeurs “connues” (ce que tu viens de sauver)
// Astuce: tu mets TOUT ce que tu passes à l’UPDATE ici, mais sans maintenance lourde :
// si tu ajoutes un champ au formulaire + UPDATE, tu l’ajoutes déjà ici de toute façon.
// Valeurs persistées à comparer avec l'état précédent de la fiche.
$new = [
'name' => $name,
'internal_code' => $internal_code,
@ -801,8 +799,7 @@ trait AnimalRecordActions
'quarantine_until' => $quarantine_until,
'fiv' => $fiv,
'felv' => $felv,
// ajoute ici uniquement les champs que tu SAUVEGARDES dans UPDATE
// (si demain tu ajoutes 3 champs au form, tu les ajouteras déjà à l’UPDATE -> copie/colle aussi ici)
// Cette liste doit rester alignée sur les champs écrits par la requête UPDATE.
];
// Champs à ignorer (bruit)

View file

@ -426,7 +426,7 @@ final class AnimalsController
throw $e;
}
// Historique (optionnel)
// Historique associé à la modification.
if (method_exists(__CLASS__, 'logHistory')) {
self::logHistory(
$animalId,
@ -486,7 +486,7 @@ final class AnimalsController
try {
$svc->refreshByChip($id, $chipId);
} catch (Throwable $e) {
// on laisse le cache en "error"
// Le cache conserve l'état d'erreur fourni par le service.
}
$cached = $svc->getCachedByAnimal($id);
$stale = $svc->isStale($cached, 86400);

View file

@ -7,7 +7,7 @@ final class GeocodeService
* Retour: ['lat'=>float, 'lng'=>float, 'display_name'=>string] ou null
*
* IMPORTANT:
* - Respecte le fair use : pas de spam (cache côté DB chez toi, et TTL)
* - Limite les appels au service grâce au cache local et à son TTL
* - User-Agent explicite
*/
public static function geocode(string $query): ?array

View file

@ -38,7 +38,7 @@ final class IcadService
return true;
}
// si en erreur → on retente
// Une entrée en erreur peut être actualisée lors d'une nouvelle tentative.
if (($cache['status'] ?? '') !== 'ok') {
return true;
}
@ -227,13 +227,13 @@ final class IcadService
return html_entity_decode($m[3], ENT_QUOTES);
}
// 2) fallback: value avant name
// 2) Accepte aussi les attributs placés dans l'ordre inverse.
$re2 = '/<input\b[^>]*\bvalue=(["\'])(.*?)\1[^>]*\bname=(["\'])' . $field . '\3[^>]*>/is';
if (preg_match($re2, $html, $m)) {
return html_entity_decode($m[2], ENT_QUOTES);
}
// 3) si fieldName == _token : on prend le 1er _token trouvé
// 3) Utilise le premier jeton générique lorsque le champ demandé est _token.
if ($fieldName === '_token') {
if (preg_match('/<input\b[^>]*\bname=(["\'])_token\1[^>]*\bvalue=(["\'])(.*?)\2[^>]*>/is', $html, $m)) {
return html_entity_decode($m[3], ENT_QUOTES);
@ -264,7 +264,7 @@ final class IcadService
return $p;
}
// fallback HTML
// Recherche de l'identifiant dans le HTML lorsque l'URL ne le contient pas.
if (preg_match('~href=["\'](/animal/\d+)["\']~', $resp['body'], $m)) {
return $m[1];
}
@ -336,9 +336,9 @@ final class IcadService
// Adresse postale: i-CAD ne la met pas toujours dans un bloc unique, mais on tente
$ownerPostal = $txt('//*[@id="down_right_block"]//*[contains(@class,"coords")]//*[contains(@class,"postal")]');
if ($ownerPostal === '') {
// fallback: parfois l’adresse est dans le même bloc coords mais pas taggée
// L'adresse peut être présente dans le bloc de coordonnées sans libellé dédié.
$coordsText = $txt('//*[@id="down_right_block"]//*[contains(@class,"coords")]');
// on évite de tout recracher, juste si on détecte des numéros/rue
// Ne conserve le bloc que s'il ressemble à une adresse postale.
$ownerPostal = $coordsText;
}

View file

@ -360,7 +360,7 @@ $data['owner'] ??
$data['detenteur'] ??
null;
// Si ton parse aplatit au lieu d'imbriquer :
// Prend également en charge une réponse aplatie.
if (!$holder && (
isset($data['holder_name']) || isset($data['holder_phone']) || isset($data['holder_email'])
)) {

View file

@ -769,7 +769,7 @@ $today = date('Y-m-d');
return true;
}
// 2) Fallback “manuel” (au cas où)
// 2) Activation manuelle si l'API Bootstrap n'est pas disponible.
tabLinks.forEach(a => a.classList.remove('active'));
document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active', 'show'));
@ -794,7 +794,7 @@ $today = date('Y-m-d');
history.replaceState(null, '', href);
});
// Si jamais "shown.bs.tab" ne déclenche pas (rare), on sauvegarde au click aussi
// Le clic maintient le fragment même si l'événement Bootstrap n'est pas émis.
a.addEventListener('click', () => {
const href = a.getAttribute('href');
if (!href) return;
@ -805,7 +805,7 @@ $today = date('Y-m-d');
// Un hash explicite est respecté ; sinon Identité est systématique.
const target = window.location.hash || '#tab-ident';
// Si bootstrap n'est pas prêt à l'instant T, on retente un peu (Tabler peut charger en bas)
// Tabler peut initialiser Bootstrap après ce script : une courte nouvelle tentative suffit.
let tries = 0;
(function retry() {
tries++;

View file

@ -3,7 +3,7 @@
/** @var array $statuses */
/** @var array $speciesOptions */
// Liste races (tu pourras l’externaliser plus tard en table ref)
// Races proposées par défaut dans le formulaire.
$breeds = [
'Chat Européen',
'Abyssin','Bengal','British Shorthair','Chartreux','Maine Coon','Norvégien',

View file

@ -49,7 +49,7 @@ function labelStatus(string $s): string
function fivFelvText(array $a): string
{
// adapte selon tes colonnes réelles (chez toi ça marche déjà côté liste)
// Les photos publiques sont privilégiées pour le document imprimable.
$fiv = (string)($a['fiv'] ?? '');
$felv = (string)($a['felv'] ?? '');
if ($fiv === '' && $felv === '') {
@ -67,7 +67,7 @@ function fivFelvText(array $a): string
if ($felv === '1') {
return 'FELV+';
}
// fallback : si tu stockes déjà du texte
// Accepte également une valeur déjà enregistrée sous forme de texte.
return trim($fiv . ' ' . $felv);
}

View file

@ -34,8 +34,7 @@
<span class="badge bg-blue-lt mb-2">1.0.0-rc.3</span>
<h3>Stabilisation avant la 1.0</h3>
<p class="text-muted">Découpage des fichiers volumineux, recherche universelle, correction de
l’installation vierge, anonymisation du dépôt, fiche Twix fictive complète et harmonisation des
sources PHP.</p>
l’installation vierge, jeu de démonstration enrichi et harmonisation de la présentation.</p>
</div>
</section>
</div>