22, 'par_prenom_nom' => 55, 'col_check' => 10, 'no_bib_remis' => 14, 'par_sexe' => 12, 'par_age' => 12, 'par_naissance' => 26, 'par_ville' => 32, 'par_telephone1' => 30, 'par_telephone2' => 30, 'par_courriel' => 40, 'par_adresse' => 40, 'par_adresse2' => 36, 'par_codepostal' => 18, 'pay_nom' => 28, 'pay_id' => 28, 'pay_iso' => 14, 'nom_equipe' => 32, 'par_nom_equipe' => 32, 'par_contact_urgence_nom' => 32, 'par_contact_urgence_telephone' => 30, ]; if (isset($tab[$strKey])) { return $tab[$strKey]; } return 28; } /** MSIN-4512 — Somme des largeurs estimées. */ function fxBibDistPrintColsWidthSumMm(array $tabKeys) { $flt = 0; foreach ($tabKeys as $strKey) { $flt += fxBibDistPrintColEstWidthMm($strKey); } return (int)ceil($flt); } /** * MSIN-4512 — Parse CSV de clés colonnes (col_check,par_sexe,que:12,…). * @return array */ function fxBibParseDistPrintColKeys($strCsv) { if ($strCsv === null || trim((string)$strCsv) === '') { return []; } $out = []; foreach (explode(',', (string)$strCsv) as $part) { $str = trim($part); if ($str === '') { continue; } if (preg_match('/^que:(\d+)$/', $str, $m)) { $str = 'que:' . (int)$m[1]; } elseif (preg_match('/^par_[a-z0-9_]+$/i', $str)) { $str = strtolower($str); } elseif (preg_match('/^(no_bib|col_check|no_bib_remis|pay_nom|pay_iso|pay_id|nom_equipe)$/i', $str)) { $str = strtolower($str); } else { continue; } if (!in_array($str, $out, true)) { $out[] = $str; } } return $out; } /** MSIN-4512 — Sérialise les clés colonnes. */ function fxBibDistPrintColKeysToCsv(array $tabKeys) { return implode(',', fxBibParseDistPrintColKeys(implode(',', $tabKeys))); } /** * MSIN-4512 — Colonnes toujours présentes sur le PDF (ordre choisissable, non retirables). * @return array */ function fxBibDistPrintMandatoryKeys() { // Défaut historique PDF : Nom/Prénom puis Dossard. return ['par_prenom_nom', 'no_bib']; } /** MSIN-4512 — true si clé obligatoire (budget optionnel non consommé). */ function fxBibDistPrintIsMandatoryKey($strKey) { return in_array(trim((string)$strKey), fxBibDistPrintMandatoryKeys(), true); } /** * MSIN-4512 — Garantit les clés obligatoires dans l’ordre (insère le défaut si absentes). * @param array $tabKeys * @return array */ function fxBibDistPrintEnsureMandatoryInOrder(array $tabKeys) { $tabOut = []; foreach ($tabKeys as $strKey) { $strKey = trim((string)$strKey); if ($strKey === '' || in_array($strKey, $tabOut, true)) { continue; } $tabOut[] = $strKey; } $tabMissing = []; foreach (fxBibDistPrintMandatoryKeys() as $strMust) { if (!in_array($strMust, $tabOut, true)) { $tabMissing[] = $strMust; } } if (!empty($tabMissing)) { $tabOut = array_merge($tabMissing, $tabOut); } return $tabOut; } /** * MSIN-4512 — Catalogue colonnes de base proposables (hors questions). * Même source fiche / Production Excel + case OK + check-in. * * @return array */ function fxBibDistPrintCollectBaseFieldOptions($int_eve_id, $strLangue = 'fr') { $int_eve_id = (int)$int_eve_id; $strLangue = ($strLangue === 'en') ? 'en' : 'fr'; $tabOut = []; $tabSeen = []; $fnAdd = function ($strKey, $strLabel) use (&$tabOut, &$tabSeen) { $strKey = trim((string)$strKey); $strLabel = trim((string)$strLabel); if ($strKey === '' || isset($tabSeen[$strKey])) { return; } // Obligatoires PDF : pas dans les chips Disponibles (déjà dans l’ordre). if (in_array($strKey, ['par_nom', 'par_prenom', 'par_prenom_nom', 'no_bib'], true)) { return; } $tabSeen[$strKey] = true; $tabOut[] = [ 'key' => $strKey, 'label' => $strLabel !== '' ? $strLabel : $strKey, 'width' => fxBibDistPrintColEstWidthMm($strKey), ]; }; $fnAdd('col_check', fxBibTexte('bib_v4_dist_print_col_check_opt', 0)); $fnAdd('no_bib_remis', fxBibTexte('bib_v4_dist_print_col_checkin', 0)); if (!function_exists('fxBibProductionGetEventInfoFields')) { $strProd = __DIR__ . '/inc_fx_bib_production.php'; if (is_file($strProd)) { require_once $strProd; } } $blnHasSexe = false; if ($int_eve_id > 0 && function_exists('fxBibProductionGetEventInfoFields')) { foreach (fxBibProductionGetEventInfoFields($int_eve_id) as $tabInfo) { $strCha = trim((string)($tabInfo['cha_nom'] ?? '')); if ($strCha === '') { continue; } if ($strCha === 'par_sexe') { $blnHasSexe = true; } $strLabel = trim((string)($tabInfo['cha_label_' . $strLangue] ?? '')); if ($strLabel === '') { $strLabel = trim((string)($tabInfo['cha_label_fr'] ?? '')); } $fnAdd($strCha, $strLabel); } } if (!$blnHasSexe) { $fnAdd('par_sexe', fxBibTexte('bib_v4_dist_print_col_sexe', 0)); } // Pays : libellé (pas l'id brut) — comme Production Excel. $fnAdd('pay_nom', fxBibTexte('bib_v5_production_field_pay_nom', 0) ?: (($strLangue === 'en') ? 'Country' : 'Pays')); $fnAdd('nom_equipe', fxBibTexte('bib_v5_production_field_nom_equipe', 0) ?: (($strLangue === 'en') ? 'Team name' : 'Nom d\'équipe')); return $tabOut; } /** * MSIN-4512 — Sélection mémorisée (ba_bib_dist_cols) avec repli legacy que_ids. * @return array */ function fxBibDistPrintResolveSelectedCols(array $eprRow, array $tabValidKeys) { $tabValid = []; foreach ($tabValidKeys as $strKey) { $tabValid[$strKey] = true; } // Obligatoires toujours valides (ordre PDF). foreach (fxBibDistPrintMandatoryKeys() as $strMust) { $tabValid[$strMust] = true; } $strCols = trim((string)($eprRow['ba_bib_dist_cols'] ?? '')); if ($strCols !== '') { $tabSel = fxBibParseDistPrintColKeys($strCols); } else { // Legacy : case OK + sexe (comportement PDF d’avant) + questions CSV. $tabSel = array_merge(fxBibDistPrintMandatoryKeys(), ['col_check', 'par_sexe']); foreach (fxBibParseDistPrintQueIds($eprRow['ba_bib_dist_que_ids'] ?? '') as $intQueId) { $tabSel[] = 'que:' . (int)$intQueId; } } $tabOut = []; foreach ($tabSel as $strKey) { if (isset($tabValid[$strKey]) && !in_array($strKey, $tabOut, true)) { $tabOut[] = $strKey; } } return fxBibDistPrintEnsureMandatoryInOrder($tabOut); } /** MSIN-4512 — Orientation mémorisée sur l’événement. */ function fxBibGetDistPrintOrient($int_eve_id) { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0) { return 'P'; } // Colonne absente tant que sql/MSIN-4512 n’est pas passé → portrait. static $blnHasCol = null; if ($blnHasCol === null) { $blnHasCol = ((int)$objDatabase->fxGetVar( "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inscriptions_evenements' AND COLUMN_NAME = 'eve_bib_dist_print_orient'" ) > 0); } if (!$blnHasCol) { return 'P'; } $str = $objDatabase->fxGetVar( "SELECT eve_bib_dist_print_orient FROM inscriptions_evenements WHERE eve_id = $int_eve_id LIMIT 1" ); return fxBibDistPrintNormalizeOrient($str); } /** MSIN-4512 — Persiste orientation listes. */ function fxBibSaveDistPrintOrient($int_eve_id, $strOrient) { global $objDatabase; $int_eve_id = (int)$int_eve_id; if ($int_eve_id <= 0) { return; } $strOrient = fxBibDistPrintNormalizeOrient($strOrient); static $blnHasCol = null; if ($blnHasCol === null) { $blnHasCol = ((int)$objDatabase->fxGetVar( "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inscriptions_evenements' AND COLUMN_NAME = 'eve_bib_dist_print_orient'" ) > 0); } if (!$blnHasCol) { return; } $objDatabase->fxQuery( "UPDATE inscriptions_evenements SET eve_bib_dist_print_orient = '" . $objDatabase->fxEscape($strOrient) . "' WHERE eve_id = $int_eve_id LIMIT 1" ); } /** * MSIN-4512 — Valeur cellule PDF pour une clé optionnelle. * MSIN-4554 — nom_equipe : pec (comme assignation) ; que: déjà enrichies en équipe via fxBibGetDistPrintQuestionAnswers. */ function fxBibDistPrintResolveColValue($strKey, array $row, array $tabAnswersByQue, $strLangue = 'fr') { $strKey = trim((string)$strKey); $strLangue = ($strLangue === 'en') ? 'en' : 'fr'; if ($strKey === 'col_check') { return ''; } if ($strKey === 'no_bib_remis') { return ((int)($row['no_bib_remis'] ?? 0) === 1) ? fxBibTexte('bib_v4_dist_print_checkin_yes', 0) : ''; } if ($strKey === 'par_sexe') { return fxBibDistPrintSexeLabel($row['par_sexe'] ?? '', $strLangue); } // MSIN-4554 — Champ cœur : même priorité que l'écran d'assignation. if ($strKey === 'nom_equipe') { $strPec = trim((string)($row['pec_nom_equipe'] ?? '')); if ($strPec !== '') { return $strPec; } return trim((string)($row['par_nom_equipe'] ?? '')); } if (preg_match('/^que:(\d+)$/', $strKey, $m)) { // MSIN-4554 — Sur épreuve équipe les réponses (dont nom d'équipe) sont // déjà enrichies dans fxBibGetDistPrintQuestionAnswers. return trim((string)($tabAnswersByQue[(int)$m[1]] ?? '')); } if (!function_exists('fxBibProductionResolveCellValue')) { $strProd = __DIR__ . '/inc_fx_bib_production.php'; if (is_file($strProd)) { require_once $strProd; } } if (function_exists('fxBibProductionResolveCellValue')) { $str = fxBibProductionResolveCellValue( $strKey, (int)($row['no_bib'] ?? 0), '', $row, $tabAnswersByQue, $strLangue ); if ($strKey === 'par_naissance' && $str !== '' && $str !== '0000-00-00') { $ts = strtotime($str); if ($ts !== false) { return date(($strLangue === 'en') ? 'Y-m-d' : 'Y-m-d', $ts); } } return $str; } return trim((string)($row[$strKey] ?? '')); } /** * MSIN-4512 — Calcule largeurs PDF pour la liste ordonnée (fixes + options). * Dossard fixe ~22 mm ; Nom/Prénom flexible ; options compressées si besoin. * * @param array $tabCols * @return array{widths:array,page:float} */ function fxBibDistPrintComputeLayoutWidths(array $tabCols, $strOrient) { $fltPage = fxBibDistPrintUsableWidthMm($strOrient); $fltBib = 22.0; $fltNameMin = 50.0; $fltOptNeed = 0.0; $blnHasName = false; $blnHasBib = false; foreach ($tabCols as $col) { $strKey = (string)($col['key'] ?? ''); if ($strKey === 'par_prenom_nom') { $blnHasName = true; continue; } if ($strKey === 'no_bib') { $blnHasBib = true; continue; } $fltOptNeed += (float)($col['width'] ?? fxBibDistPrintColEstWidthMm($strKey)); } $fltReserved = ($blnHasBib ? $fltBib : 0.0); $fltRemain = max(10.0, $fltPage - $fltReserved); $fltName = $blnHasName ? $fltNameMin : 0.0; $fltForOpts = max(0.0, $fltRemain - $fltName); $fltScale = ($fltOptNeed > 0 && $fltOptNeed > $fltForOpts) ? ($fltForOpts / $fltOptNeed) : 1.0; if ($blnHasName && $fltScale >= 1.0) { $fltName = max($fltNameMin, $fltRemain - $fltOptNeed); $fltScale = 1.0; } $tabW = []; foreach ($tabCols as $col) { $strKey = (string)($col['key'] ?? ''); if ($strKey === '') { continue; } if ($strKey === 'no_bib') { $tabW[$strKey] = $fltBib; continue; } if ($strKey === 'par_prenom_nom') { $tabW[$strKey] = max($fltNameMin, $fltName); continue; } $fltW = (float)($col['width'] ?? fxBibDistPrintColEstWidthMm($strKey)) * $fltScale; $tabW[$strKey] = max(8.0, $fltW); } return [ 'widths' => $tabW, 'page' => $fltPage, // Compat anciens appelants éventuels. 'name' => $tabW['par_prenom_nom'] ?? $fltName, 'bib' => $tabW['no_bib'] ?? $fltBib, 'opts' => array_filter($tabW, function ($k) { return !fxBibDistPrintIsMandatoryKey($k); }, ARRAY_FILTER_USE_KEY), ]; }