$digit) { $number = (int) $digit * ($index % 2 === 0 ? 2 : 1); $sum += $number > 9 ? $number - 9 : $number; } return $sum % 10 === 0; } public static function slugifyUpper(string $s): string { $s = trim($s); if ($s === '') { return 'SANS-NOM'; } // translit: accents -> ascii (si dispo) $t = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); if ($t !== false) { $s = $t; } $s = strtoupper($s); $s = preg_replace('/[^A-Z0-9]+/', '-', $s) ?? $s; $s = trim($s, '-'); return $s !== '' ? $s : 'SANS-NOM'; } public static function nextAnimalCode(string $name, ?int $year = null): string { $year = $year ?? (int) date('Y'); $slug = self::slugifyUpper($name); $db = DB::pdo(); $stmt = $db->prepare( 'SELECT internal_code FROM animals WHERE internal_code LIKE :p ORDER BY internal_code DESC LIMIT 1', ); $stmt->execute([':p' => $year . '-%']); $last = (string) ($stmt->fetchColumn() ?: ''); $n = 1; if ($last !== '') { // format attendu: YYYY-NNN-... $parts = explode('-', $last); if (count($parts) >= 2 && ctype_digit($parts[1])) { $n = (int) $parts[1] + 1; } } return sprintf('%d-%03d-%s', $year, $n, $slug); } }