Files
ms1inscription-v5/php/inc_fx_bib_dist_print.php

441 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* MSIN-4512 — PDF distribution dossards : colonnes de base, check-in, orientation listes.
* Complète les fonctions DistPrint de php/inc_fx_promoteur.php.
*/
/** MSIN-4512 — Orientation listes : P portrait / L paysage. */
function fxBibDistPrintNormalizeOrient($strOrient) {
$strOrient = strtoupper(trim((string)$strOrient));
return ($strOrient === 'L') ? 'L' : 'P';
}
/** MSIN-4512 — Largeur utile page lettre (mm), hors marges 10+10. */
function fxBibDistPrintUsableWidthMm($strOrient) {
$strOrient = fxBibDistPrintNormalizeOrient($strOrient);
// Letter : 215.9 × 279.4 mm
return ($strOrient === 'L') ? 259.4 : 195.9;
}
/** MSIN-4512 — Réservé dossard + nom/prénom (mm). */
function fxBibDistPrintMandatoryWidthMm() {
return 22 + 55;
}
/** MSIN-4512 — Budget mm pour colonnes optionnelles. */
function fxBibDistPrintOptionalBudgetMm($strOrient) {
return max(20, (int)floor(fxBibDistPrintUsableWidthMm($strOrient) - fxBibDistPrintMandatoryWidthMm()));
}
/**
* MSIN-4512 — Largeur estimée d'une colonne optionnelle (mm).
*/
function fxBibDistPrintColEstWidthMm($strKey) {
$strKey = trim((string)$strKey);
if ($strKey === '') {
return 0;
}
if (preg_match('/^que:\d+$/', $strKey)) {
return 28;
}
static $tab = [
'no_bib' => 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<int, string>
*/
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<int, string>
*/
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 lordre (insère le défaut si absentes).
* @param array<int, string> $tabKeys
* @return array<int, string>
*/
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<int, array{key:string,label:string,width:int}>
*/
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 lordre).
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<int, string>
*/
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 davant) + 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 nest 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<int, array{key:string,label:string,width?:int}> $tabCols
* @return array{widths:array<string,float>,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),
];
}