Files
ms1inscription-v5/php/chronotrack_api/fx_chronotrack_events.php

986 lines
34 KiB
PHP

<?php
/**
* MSIN API ChronoTrack — lecture / filtrage des ressources CT (event, race).
*/
function fxChronotrackApiNormalizeEntityList($mixPayload, $strEntityKey) {
$arrOut = array();
if (!is_array($mixPayload)) {
return $arrOut;
}
if (isset($mixPayload[$strEntityKey]) && is_array($mixPayload[$strEntityKey])) {
$mixList = $mixPayload[$strEntityKey];
if (fxChronotrackApiIsAssocArray($mixList)) {
$arrOut[] = $mixList;
} else {
$arrOut = $mixList;
}
return $arrOut;
}
// Pluriel courant côté CT (ex. "races" pour clé "race")
$strPluralKey = $strEntityKey . 's';
if ($strEntityKey !== $strPluralKey && isset($mixPayload[$strPluralKey]) && is_array($mixPayload[$strPluralKey])) {
$mixList = $mixPayload[$strPluralKey];
if (fxChronotrackApiIsAssocArray($mixList)) {
$arrOut[] = $mixList;
} else {
$arrOut = $mixList;
}
return $arrOut;
}
// Clé CT Live pour GET event/{id}/race (ex. event_race, pas race)
if ($strEntityKey === 'race') {
foreach (array('event_race') as $strAltKey) {
if (!isset($mixPayload[$strAltKey]) || !is_array($mixPayload[$strAltKey])) {
continue;
}
$mixList = $mixPayload[$strAltKey];
if (fxChronotrackApiIsAssocArray($mixList)) {
$arrOut[] = $mixList;
} else {
$arrOut = $mixList;
}
return $arrOut;
}
}
// MSIN-4328 — clé CT pour reg_choice (souvent event_reg_choice)
if ($strEntityKey === 'reg_choice') {
foreach (array('event_reg_choice', 'registration_choice') as $strAltKey) {
if (!isset($mixPayload[$strAltKey]) || !is_array($mixPayload[$strAltKey])) {
continue;
}
$mixList = $mixPayload[$strAltKey];
if (fxChronotrackApiIsAssocArray($mixList)) {
$arrOut[] = $mixList;
} else {
$arrOut = $mixList;
}
return $arrOut;
}
}
// Clé CT Live pour GET event/{id}/entry (ex. event_entry, pas entry)
if ($strEntityKey === 'entry') {
foreach (array('event_entry', 'entries') as $strAltKey) {
if (!isset($mixPayload[$strAltKey]) || !is_array($mixPayload[$strAltKey])) {
continue;
}
$mixList = $mixPayload[$strAltKey];
if (fxChronotrackApiIsAssocArray($mixList)) {
$arrOut[] = $mixList;
} else {
$arrOut = $mixList;
}
return $arrOut;
}
}
if (fxChronotrackApiIsAssocArray($mixPayload) && (
isset($mixPayload['race_id']) || isset($mixPayload['reg_choice_id'])
|| isset($mixPayload['entry_id']) || isset($mixPayload['external_id'])
)) {
return array($mixPayload);
}
if (fxChronotrackApiIsAssocArray($mixPayload) && isset($mixPayload['id'])
&& !isset($mixPayload['event_id']) && !isset($mixPayload['event_name'])
) {
return array($mixPayload);
}
if (!fxChronotrackApiIsAssocArray($mixPayload)) {
return $mixPayload;
}
return $arrOut;
}
function fxChronotrackApiIsAssocArray($arr) {
if (!is_array($arr) || $arr === array()) {
return false;
}
return array_keys($arr) !== range(0, count($arr) - 1);
}
function fxChronotrackApiEntityId($arrEntity) {
foreach (array('entry_id', 'reg_choice_id', 'race_id', 'event_id', 'id') as $strKey) {
if (isset($arrEntity[$strKey]) && $arrEntity[$strKey] !== '') {
return (string)$arrEntity[$strKey];
}
}
return '';
}
function fxChronotrackApiEntityExternalId($arrEntity) {
foreach (array('external_id', 'entry_external_id', 'ext_id', 'external_entry_id') as $strKey) {
if (isset($arrEntity[$strKey]) && $arrEntity[$strKey] !== '') {
return (string)$arrEntity[$strKey];
}
}
return '';
}
function fxChronotrackApiEntityEntryLabel($arrEntity) {
$strFirst = fxChronotrackApiRaceField($arrEntity, array('first_name', 'entry_first_name', 'fname'));
$strLast = fxChronotrackApiRaceField($arrEntity, array('last_name', 'entry_last_name', 'lname'));
if ($strFirst !== '' || $strLast !== '') {
return trim($strFirst . ' ' . $strLast);
}
return fxChronotrackApiEntityName($arrEntity);
}
function fxChronotrackApiEntityName($arrEntity) {
foreach (array(
'reg_choice_name', 'registration_choice_name', 'choice_name',
'event_name', 'race_name', 'name', 'title',
'entry_name', 'athlete_name',
) as $strKey) {
if (!empty($arrEntity[$strKey])) {
return trim((string)$arrEntity[$strKey]);
}
}
return '';
}
function fxChronotrackApiRaceField($arrEntity, $arrKeys) {
foreach ($arrKeys as $strKey) {
if (!isset($arrEntity[$strKey])) {
continue;
}
$strVal = trim((string)$arrEntity[$strKey]);
if ($strVal !== '') {
return $strVal;
}
}
return '';
}
function fxChronotrackApiFormatRaceDistanceLabel($arrEntity) {
$strDist = fxChronotrackApiRaceField($arrEntity, array(
'race_course_distance', 'course_distance', 'race_distance', 'distance', 'race_length',
));
if ($strDist === '') {
return '';
}
$strUnit = fxChronotrackApiRaceField($arrEntity, array(
'race_pref_distance_unit', 'course_distance_type', 'course_distance_unit',
'distance_unit', 'race_distance_unit', 'distance_type',
));
if (is_numeric($strDist) && $strUnit !== '') {
$fltDist = floatval($strDist);
if ($strUnit === 'kilometers' && $fltDist >= 1000) {
$strDist = rtrim(rtrim(number_format($fltDist / 1000, 1, '.', ''), '0'), '.') . ' km';
return $strDist;
}
if ($strUnit === 'meters') {
$strDist = rtrim(rtrim(number_format($fltDist, 0, '.', ''), '0'), '.') . ' m';
return $strDist;
}
}
if ($strUnit !== '' && stripos($strDist, $strUnit) === false) {
return $strDist . ' ' . $strUnit;
}
return $strDist;
}
function fxChronotrackApiFormatRaceTeamLabel($arrEntity) {
foreach (array('team_race', 'is_team_race', 'team') as $strKey) {
if (!isset($arrEntity[$strKey])) {
continue;
}
$mixVal = $arrEntity[$strKey];
if ($mixVal === true || $mixVal === 1 || $mixVal === '1' || strtolower((string)$mixVal) === 'true' || strtolower((string)$mixVal) === 'yes') {
return 'Équipe';
}
if ($mixVal === false || $mixVal === 0 || $mixVal === '0' || strtolower((string)$mixVal) === 'false' || strtolower((string)$mixVal) === 'no') {
return 'Individuel';
}
}
$strSubtype = strtolower(fxChronotrackApiRaceField($arrEntity, array('race_subtype', 'subtype', 'participant_type')));
if ($strSubtype !== '') {
if (strpos($strSubtype, 'team') !== false) {
return 'Équipe';
}
if (strpos($strSubtype, 'individual') !== false || strpos($strSubtype, 'individ') !== false) {
return 'Individuel';
}
}
return '';
}
function fxChronotrackApiFormatRaceRegChoicesLabel($arrEntity) {
foreach (array('reg_choice', 'reg_choices', 'registration_choices', 'choices') as $strKey) {
if (!isset($arrEntity[$strKey]) || !is_array($arrEntity[$strKey])) {
continue;
}
$arrNames = array();
$arrList = $arrEntity[$strKey];
if (fxChronotrackApiIsAssocArray($arrList) && (
isset($arrList['reg_choice_name']) || isset($arrList['name']) || isset($arrList['label'])
)) {
$arrList = array($arrList);
}
foreach ($arrList as $arrChoice) {
if (!is_array($arrChoice)) {
continue;
}
$strChoice = fxChronotrackApiRaceField($arrChoice, array(
'reg_choice_name', 'registration_choice_name', 'choice_name', 'name', 'label',
));
if ($strChoice !== '') {
$arrNames[] = $strChoice;
}
}
if (count($arrNames) > 0) {
return implode(', ', array_values(array_unique($arrNames)));
}
}
return '';
}
function fxChronotrackApiFormatRaceLabel($arrEntity) {
// MSIN-4328 — nom de race seul ; le reg_choice est ajouté au mapping via ApplyRegChoiceLabels
$strName = fxChronotrackApiRaceField($arrEntity, array('race_name', 'display_name', 'name', 'title'));
if ($strName !== '') {
return $strName;
}
$strTag = fxChronotrackApiRaceField($arrEntity, array('race_tag', 'tag'));
$strType = fxChronotrackApiRaceField($arrEntity, array('race_type', 'sport', 'race_course_type'));
$strDist = fxChronotrackApiFormatRaceDistanceLabel($arrEntity);
$strTeam = fxChronotrackApiFormatRaceTeamLabel($arrEntity);
$arrExtras = array();
if ($strTag !== '') {
$arrExtras[] = 'tag ' . $strTag;
}
if ($strType !== '') {
$arrExtras[] = $strType;
}
if ($strDist !== '') {
$arrExtras[] = $strDist;
}
if ($strTeam !== '') {
$arrExtras[] = $strTeam;
}
$arrExtras = array_values(array_unique($arrExtras));
$strName = $strDist !== '' ? $strDist : ('Race ' . fxChronotrackApiEntityId($arrEntity));
if (count($arrExtras) === 0) {
return $strName;
}
return $strName . ' — ' . implode(' · ', $arrExtras);
}
/**
* MSIN-4328 — Fusionne deux index race_id → noms reg_choice.
*
* @param array<int, string[]> $arrA
* @param array<int, string[]> $arrB
* @return array<int, string[]>
*/
function fxChronotrackApiMergeRegChoiceNamesByRaceId($arrA, $arrB) {
if (!is_array($arrA)) {
$arrA = array();
}
if (!is_array($arrB) || count($arrB) === 0) {
return $arrA;
}
foreach ($arrB as $intRaceId => $arrNames) {
$intRaceId = intval($intRaceId);
if ($intRaceId <= 0 || !is_array($arrNames)) {
continue;
}
if (!isset($arrA[$intRaceId])) {
$arrA[$intRaceId] = array();
}
foreach ($arrNames as $strName) {
$strName = trim((string)$strName);
if ($strName === '') {
continue;
}
$arrA[$intRaceId][] = $strName;
}
$arrA[$intRaceId] = array_values(array_unique($arrA[$intRaceId]));
}
return $arrA;
}
/**
* MSIN-4328 — Indexe les noms de reg_choice par race_id parent (payload event/race).
*
* @return array<int, string[]>
*/
function fxChronotrackApiRegChoiceNamesByRaceId($mixPayload) {
$arrByRace = array();
foreach (fxChronotrackApiCollectRegChoiceEntities($mixPayload) as $arrChoice) {
if (!is_array($arrChoice)) {
continue;
}
$intParent = intval(fxChronotrackApiRaceField($arrChoice, array('race_id', 'event_race_id')));
if ($intParent <= 0 && isset($arrChoice['race']) && is_array($arrChoice['race'])) {
$intParent = intval(fxChronotrackApiEntityId($arrChoice['race']));
}
if ($intParent <= 0) {
continue;
}
$strName = fxChronotrackApiRaceField($arrChoice, array(
'reg_choice_name', 'registration_choice_name', 'choice_name', 'display_name', 'name', 'title',
));
if ($strName === '' && isset($arrChoice['reg_choice_id']) && $arrChoice['reg_choice_id'] !== '') {
$strName = 'reg_choice ' . $arrChoice['reg_choice_id'];
}
if ($strName === '') {
continue;
}
if (!isset($arrByRace[$intParent])) {
$arrByRace[$intParent] = array();
}
$arrByRace[$intParent][] = $strName;
}
foreach ($arrByRace as $intRaceId => $arrNames) {
$arrByRace[$intRaceId] = array_values(array_unique($arrNames));
}
return $arrByRace;
}
/**
* MSIN-4328 — Filet : déduit race_id → reg_choice_name depuis les entries CT.
*
* @return array<int, string[]>
*/
function fxChronotrackApiRegChoiceNamesFromEntriesPayload($mixPayload) {
$arrByRace = array();
$arrEntries = fxChronotrackApiNormalizeEntityList($mixPayload, 'entry');
if (count($arrEntries) === 0 && is_array($mixPayload) && isset($mixPayload['event']) && is_array($mixPayload['event'])) {
$arrEntries = fxChronotrackApiNormalizeEntityList($mixPayload['event'], 'entry');
}
foreach ($arrEntries as $arrEntry) {
if (!is_array($arrEntry)) {
continue;
}
$intRaceId = intval(fxChronotrackApiRaceField($arrEntry, array('race_id', 'event_race_id')));
if ($intRaceId <= 0) {
continue;
}
$strName = fxChronotrackApiRaceField($arrEntry, array(
'reg_choice_name', 'registration_choice_name', 'choice_name',
));
if ($strName === '') {
continue;
}
if (!isset($arrByRace[$intRaceId])) {
$arrByRace[$intRaceId] = array();
}
$arrByRace[$intRaceId][] = $strName;
}
foreach ($arrByRace as $intRaceId => $arrNames) {
$arrByRace[$intRaceId] = array_values(array_unique($arrNames));
}
return $arrByRace;
}
/**
* MSIN-4328 — Ajoute « (reg_choice) » au label de chaque course du mapping.
*/
function fxChronotrackApiApplyRegChoiceLabelsToRaceRows(&$arrRaceRows, $arrNamesByRaceId) {
if (!is_array($arrRaceRows) || !is_array($arrNamesByRaceId)) {
return;
}
foreach ($arrRaceRows as &$arrRow) {
if (!is_array($arrRow)) {
continue;
}
$intId = intval($arrRow['ct_race_id'] ?? 0);
$strRc = '';
if ($intId > 0 && !empty($arrNamesByRaceId[$intId]) && is_array($arrNamesByRaceId[$intId])) {
$strRc = implode(', ', $arrNamesByRaceId[$intId]);
}
if ($strRc === '' && isset($arrRow['raw']) && is_array($arrRow['raw'])) {
$strRc = fxChronotrackApiFormatRaceRegChoicesLabel($arrRow['raw']);
if ($strRc === '') {
$strRc = fxChronotrackApiRaceField($arrRow['raw'], array(
'reg_choice_name', 'registration_choice_name', 'choice_name', 'reg_choice_label',
));
}
}
if ($strRc === '') {
continue;
}
$arrRow['reg_choice_label'] = $strRc;
$strBase = isset($arrRow['name']) && $arrRow['name'] !== ''
? $arrRow['name']
: (isset($arrRow['label']) ? $arrRow['label'] : 'Course');
// Évite double parenthèses si FormatRaceLabel a déjà collé le même texte
$strExpected = $strBase . ' (' . $strRc . ')';
if (!isset($arrRow['label']) || $arrRow['label'] !== $strExpected) {
$arrRow['label'] = $strExpected;
}
}
unset($arrRow);
}
function fxChronotrackApiEntityStartEpoch($arrEntity) {
foreach (array(
'race_planned_start_time', 'race_start_time', 'event_start_time',
'start_time', 'start_date', 'event_date',
) as $strKey) {
if (!isset($arrEntity[$strKey]) || $arrEntity[$strKey] === '' || $arrEntity[$strKey] === null) {
continue;
}
$mixVal = $arrEntity[$strKey];
if (is_numeric($mixVal)) {
return intval($mixVal);
}
$intTs = strtotime((string)$mixVal);
if ($intTs !== false) {
return $intTs;
}
}
return 0;
}
function fxChronotrackApiFormatEventRow($arrEntity) {
$intStart = fxChronotrackApiEntityStartEpoch($arrEntity);
return array(
'ct_event_id' => fxChronotrackApiEntityId($arrEntity),
'name' => fxChronotrackApiEntityName($arrEntity),
'start_epoch' => $intStart,
'start_label' => $intStart > 0 ? date('Y-m-d H:i', $intStart) : '',
'is_past' => ($intStart > 0 && $intStart < strtotime('today')),
'raw' => $arrEntity,
);
}
function fxChronotrackApiFetchEventsRaw() {
$arrApi = fxChronotrackApiOAuthApiGet('event');
if ($arrApi['state'] !== 'ok') {
return $arrApi;
}
$arrList = fxChronotrackApiNormalizeEntityList($arrApi['json'], 'event');
$arrRows = array();
foreach ($arrList as $arrEntity) {
if (!is_array($arrEntity)) {
continue;
}
$arrRow = fxChronotrackApiFormatEventRow($arrEntity);
if ($arrRow['ct_event_id'] === '') {
continue;
}
$arrRows[] = $arrRow;
}
return array('state' => 'ok', 'events' => $arrRows);
}
function fxChronotrackApiFilterEvents($arrEvents, $strSearch = '', $blnShowPast = false) {
$strSearch = mb_strtolower(trim($strSearch), 'UTF-8');
$arrFiltered = array();
foreach ($arrEvents as $arrEvent) {
if (!$blnShowPast && !empty($arrEvent['is_past'])) {
continue;
}
if ($strSearch !== '') {
$strHay = mb_strtolower($arrEvent['name'] . ' ' . $arrEvent['ct_event_id'], 'UTF-8');
if (mb_strpos($strHay, $strSearch, 0, 'UTF-8') === false) {
continue;
}
}
$arrFiltered[] = $arrEvent;
}
usort($arrFiltered, function ($a, $b) {
$intA = intval($a['start_epoch']);
$intB = intval($b['start_epoch']);
if ($intA === $intB) {
return strcasecmp($a['name'], $b['name']);
}
if ($intA <= 0) {
return 1;
}
if ($intB <= 0) {
return -1;
}
return ($intA < $intB) ? -1 : 1;
});
return $arrFiltered;
}
function fxChronotrackApiFetchEventsFiltered($strSearch = '', $blnShowPast = false) {
$arrRaw = fxChronotrackApiFetchEventsRaw();
if ($arrRaw['state'] !== 'ok') {
return $arrRaw;
}
return array(
'state' => 'ok',
'events' => fxChronotrackApiFilterEvents($arrRaw['events'], $strSearch, $blnShowPast),
'total' => count($arrRaw['events']),
);
}
function fxChronotrackApiEntityBelongsToEvent($arrEntity, $intCtEventId) {
if ($intCtEventId <= 0) {
return true;
}
foreach (array('event_id', 'event') as $strKey) {
if (!isset($arrEntity[$strKey])) {
continue;
}
$mixVal = $arrEntity[$strKey];
if (is_array($mixVal)) {
$mixVal = $mixVal['event_id'] ?? $mixVal['id'] ?? null;
}
if ($mixVal !== null && $mixVal !== '' && intval($mixVal) !== $intCtEventId) {
return false;
}
}
return true;
}
function fxChronotrackApiFormatRegChoiceRow($arrEntity) {
$strName = fxChronotrackApiRaceField($arrEntity, array(
'reg_choice_name', 'registration_choice_name', 'choice_name', 'display_name', 'name', 'title',
));
$intParentRaceId = intval(fxChronotrackApiRaceField($arrEntity, array('race_id')));
$arrExtras = array();
if (isset($arrEntity['race']) && is_array($arrEntity['race'])) {
$strRaceName = fxChronotrackApiEntityName($arrEntity['race']);
$strDist = fxChronotrackApiFormatRaceDistanceLabel($arrEntity['race']);
if ($strRaceName !== '' && strcasecmp($strRaceName, $strName) !== 0) {
$arrExtras[] = $strRaceName;
} elseif ($strDist !== '' && stripos($strName, $strDist) === false) {
$arrExtras[] = $strDist;
}
$strTeam = fxChronotrackApiFormatRaceTeamLabel($arrEntity['race']);
if ($strTeam !== '') {
$arrExtras[] = $strTeam;
}
}
$strLabel = $strName;
if ($strLabel === '') {
$strLabel = 'Choix d\'inscription ' . fxChronotrackApiEntityId($arrEntity);
} elseif (count($arrExtras) > 0) {
$strLabel .= ' · ' . implode(' · ', array_values(array_unique($arrExtras)));
}
return array(
'ct_race_id' => fxChronotrackApiEntityId($arrEntity),
'kind' => 'reg_choice',
'name' => $strName !== '' ? $strName : $strLabel,
'label' => $strLabel,
'parent_race_id' => $intParentRaceId > 0 ? $intParentRaceId : null,
'start_label' => '',
'raw' => $arrEntity,
);
}
function fxChronotrackApiCollectRegChoiceEntities($mixPayload) {
$arrById = array();
if (!is_array($mixPayload)) {
return array();
}
$arrScopes = array($mixPayload);
if (isset($mixPayload['event']) && is_array($mixPayload['event'])) {
$arrScopes[] = $mixPayload['event'];
}
foreach ($arrScopes as $arrScope) {
if (!is_array($arrScope)) {
continue;
}
$arrList = fxChronotrackApiNormalizeEntityList($arrScope, 'reg_choice');
foreach ($arrList as $arrEntity) {
if (!is_array($arrEntity) || !isset($arrEntity['reg_choice_id'])) {
continue;
}
$strId = (string)$arrEntity['reg_choice_id'];
$arrById[$strId] = $arrEntity;
}
$arrRaces = fxChronotrackApiNormalizeEntityList($arrScope, 'race');
foreach ($arrRaces as $arrRace) {
if (!is_array($arrRace) || !isset($arrRace['race_id'])) {
continue;
}
$arrChoices = fxChronotrackApiNormalizeEntityList($arrRace, 'reg_choice');
foreach ($arrChoices as $arrChoice) {
if (!is_array($arrChoice) || !isset($arrChoice['reg_choice_id'])) {
continue;
}
$strId = (string)$arrChoice['reg_choice_id'];
if (!isset($arrChoice['race']) || !is_array($arrChoice['race'])) {
$arrChoice['race'] = $arrRace;
}
$arrById[$strId] = $arrChoice;
}
}
}
return array_values($arrById);
}
function fxChronotrackApiCollectRaceEntities($mixPayload) {
$arrById = array();
if (!is_array($mixPayload)) {
return array();
}
$arrScopes = array($mixPayload);
if (isset($mixPayload['event']) && is_array($mixPayload['event'])) {
$arrScopes[] = $mixPayload['event'];
}
foreach ($arrScopes as $arrScope) {
if (!is_array($arrScope)) {
continue;
}
$arrList = fxChronotrackApiNormalizeEntityList($arrScope, 'race');
foreach ($arrList as $arrEntity) {
if (!is_array($arrEntity) || !isset($arrEntity['race_id'])) {
continue;
}
$strId = (string)$arrEntity['race_id'];
$arrById[$strId] = $arrEntity;
}
}
return array_values($arrById);
}
function fxChronotrackApiParseRegChoiceRowsFromPayload($mixPayload, $intCtEventId = 0) {
$arrRows = array();
$arrEntities = fxChronotrackApiCollectRegChoiceEntities($mixPayload);
foreach ($arrEntities as $arrEntity) {
if ($intCtEventId > 0 && !fxChronotrackApiEntityBelongsToEvent($arrEntity, $intCtEventId)) {
continue;
}
$arrRow = fxChronotrackApiFormatRegChoiceRow($arrEntity);
if ($arrRow['ct_race_id'] === '') {
continue;
}
$arrRows[$arrRow['ct_race_id']] = $arrRow;
}
$arrRows = array_values($arrRows);
usort($arrRows, function ($a, $b) {
return strcasecmp($a['name'], $b['name']);
});
return $arrRows;
}
function fxChronotrackApiFetchRegChoicesForEvent($intCtEventId) {
$intCtEventId = intval($intCtEventId);
if ($intCtEventId <= 0) {
return array('state' => 'error', 'message' => 'event_id CT invalide');
}
$arrApi = fxChronotrackApiOAuthApiGet('event/' . $intCtEventId);
if ($arrApi['state'] !== 'ok') {
return array(
'state' => 'error',
'message' => $arrApi['message'] ?? 'Impossible de lire l\'événement ChronoTrack',
);
}
$arrRows = fxChronotrackApiParseRegChoiceRowsFromPayload($arrApi['json'], $intCtEventId);
if (count($arrRows) > 0) {
return array(
'state' => 'ok',
'races' => $arrRows,
'source' => 'event/' . $intCtEventId,
'kind' => 'reg_choice',
);
}
return array('state' => 'ok', 'races' => array(), 'kind' => 'reg_choice');
}
function fxChronotrackApiFormatRaceRow($arrEntity) {
$intStart = fxChronotrackApiEntityStartEpoch($arrEntity);
$strLabel = fxChronotrackApiFormatRaceLabel($arrEntity);
return array(
'ct_race_id' => fxChronotrackApiEntityId($arrEntity),
'kind' => 'race',
'name' => fxChronotrackApiEntityName($arrEntity),
'label' => $strLabel,
'race_tag' => fxChronotrackApiRaceField($arrEntity, array('race_tag', 'tag')),
'race_type' => fxChronotrackApiRaceField($arrEntity, array('race_type', 'sport')),
'distance' => fxChronotrackApiFormatRaceDistanceLabel($arrEntity),
'team_mode' => fxChronotrackApiFormatRaceTeamLabel($arrEntity),
'start_label' => $intStart > 0 ? date('Y-m-d H:i', $intStart) : '',
'raw' => $arrEntity,
);
}
function fxChronotrackApiParseRaceRowsFromPayload($mixPayload, $intCtEventId = 0) {
$arrRows = array();
$arrEntities = fxChronotrackApiCollectRaceEntities($mixPayload);
foreach ($arrEntities as $arrEntity) {
if ($intCtEventId > 0 && !fxChronotrackApiEntityBelongsToEvent($arrEntity, $intCtEventId)) {
continue;
}
$arrRow = fxChronotrackApiFormatRaceRow($arrEntity);
if ($arrRow['ct_race_id'] === '') {
continue;
}
$arrRows[$arrRow['ct_race_id']] = $arrRow;
}
$arrRows = array_values($arrRows);
usort($arrRows, function ($a, $b) {
return strcasecmp($a['name'], $b['name']);
});
return $arrRows;
}
function fxChronotrackApiFetchRacesForEvent($intCtEventId) {
$intCtEventId = intval($intCtEventId);
if ($intCtEventId <= 0) {
return array('state' => 'error', 'message' => 'event_id CT invalide');
}
if (!fxChronotrackApiSettingsConfigured()) {
return array('state' => 'error', 'message' => fxChronotrackApiSettingsErrorMessage());
}
$strRacePath = 'event/' . $intCtEventId . '/race';
$arrApi = fxChronotrackApiOAuthApiGet($strRacePath);
if ($arrApi['state'] !== 'ok') {
return array(
'state' => 'error',
'message' => $arrApi['message'] ?? 'Impossible de lire les courses ChronoTrack',
);
}
$arrRaceRows = fxChronotrackApiParseRaceRowsFromPayload($arrApi['json'], $intCtEventId);
// MSIN-4328 — enrichir libellés dropdown CT : race_name (reg_choice)
$arrNamesByRace = fxChronotrackApiRegChoiceNamesByRaceId($arrApi['json']);
if (count($arrRaceRows) > 0) {
$arrEventApi = fxChronotrackApiOAuthApiGet('event/' . $intCtEventId);
if (($arrEventApi['state'] ?? '') === 'ok') {
$arrNamesByRace = fxChronotrackApiMergeRegChoiceNamesByRaceId(
$arrNamesByRace,
fxChronotrackApiRegChoiceNamesByRaceId($arrEventApi['json'] ?? null)
);
}
// Filet : noms visibles CT souvent présents sur les entries
if (count($arrNamesByRace) === 0) {
$arrEntryApi = fxChronotrackApiOAuthApiGet('event/' . $intCtEventId . '/entry');
if (($arrEntryApi['state'] ?? '') === 'ok') {
$arrNamesByRace = fxChronotrackApiRegChoiceNamesFromEntriesPayload(
$arrEntryApi['json'] ?? null
);
}
}
}
fxChronotrackApiApplyRegChoiceLabelsToRaceRows($arrRaceRows, $arrNamesByRace);
if (count($arrRaceRows) > 0) {
return array(
'state' => 'ok',
'races' => $arrRaceRows,
'source' => $strRacePath,
'kind' => 'race',
);
}
return array(
'state' => 'ok',
'races' => array(),
'kind' => 'race',
'message' => 'Aucune course dans GET ' . $strRacePath
. ' (clé attendue : event_race).',
);
}
function fxChronotrackApiDiagnosticEntitySamples($mixPayload, $strEntityKey, $intMax = 8) {
if ($strEntityKey === 'reg_choice') {
$arrEntities = fxChronotrackApiCollectRegChoiceEntities($mixPayload);
} elseif ($strEntityKey === 'race') {
$arrEntities = fxChronotrackApiCollectRaceEntities($mixPayload);
} elseif ($strEntityKey === 'entry') {
$arrEntities = fxChronotrackApiNormalizeEntityList($mixPayload, 'entry');
} else {
$arrEntities = fxChronotrackApiNormalizeEntityList($mixPayload, $strEntityKey);
}
$arrSamples = array();
foreach ($arrEntities as $arrEntity) {
if (!is_array($arrEntity)) {
continue;
}
if ($strEntityKey === 'entry') {
$strId = fxChronotrackApiEntityId($arrEntity);
if ($strId === '') {
$strId = fxChronotrackApiEntityExternalId($arrEntity);
}
if ($strId === '') {
continue;
}
$arrSamples[$strId] = array(
'id' => $strId,
'external_id' => fxChronotrackApiEntityExternalId($arrEntity),
'name' => fxChronotrackApiEntityEntryLabel($arrEntity),
'bib' => fxChronotrackApiRaceField($arrEntity, array('bib', 'bib_number', 'entry_bib')),
'entry_status'=> fxChronotrackApiRaceField($arrEntity, array('entry_status', 'status')),
'race_id' => fxChronotrackApiRaceField($arrEntity, array('race_id', 'event_race_id')),
'country_code'=> fxChronotrackApiRaceField($arrEntity, array('country_code', 'country', 'country_iso')),
'state_code' => fxChronotrackApiRaceField($arrEntity, array('state_code', 'state', 'province_code')),
'keys' => array_slice(array_keys($arrEntity), 0, 32),
);
continue;
}
$strId = fxChronotrackApiEntityId($arrEntity);
if ($strId === '') {
continue;
}
$arrSamples[$strId] = array(
'id' => $strId,
'name' => fxChronotrackApiEntityName($arrEntity),
'keys' => array_slice(array_keys($arrEntity), 0, 24),
);
}
$arrSamples = array_values($arrSamples);
return array(
'count' => count($arrSamples),
'samples' => array_slice($arrSamples, 0, $intMax),
);
}
function fxChronotrackApiDiagnosticSummarizeEntryPayload($mixJson) {
if (!is_array($mixJson)) {
return array(
'top_keys' => array(),
'entry' => array('count' => 0, 'samples' => array(), 'field_keys' => array()),
);
}
$arrEntry = fxChronotrackApiDiagnosticEntitySamples($mixJson, 'entry', 5);
$arrFieldKeys = array();
if (!empty($arrEntry['samples'][0]['keys'])) {
$arrFieldKeys = $arrEntry['samples'][0]['keys'];
}
return array(
'top_keys' => array_slice(array_keys($mixJson), 0, 40),
'entry' => $arrEntry,
'field_keys' => $arrFieldKeys,
);
}
function fxChronotrackApiDiagnosticSummarizePayload($mixJson) {
if (!is_array($mixJson)) {
return array(
'top_keys' => array(),
'reg_choice' => array('count' => 0, 'samples' => array()),
'race' => array('count' => 0, 'samples' => array()),
);
}
return array(
'top_keys' => array_slice(array_keys($mixJson), 0, 40),
'event_race' => fxChronotrackApiDiagnosticEntitySamples(
is_array($mixJson) && isset($mixJson['event_race']) ? array('event_race' => $mixJson['event_race']) : $mixJson,
'race'
),
'reg_choice' => fxChronotrackApiDiagnosticEntitySamples($mixJson, 'reg_choice'),
'race' => fxChronotrackApiDiagnosticEntitySamples($mixJson, 'race'),
);
}
function fxChronotrackApiDiagnosticEncodeJson($mixJson) {
$strRaw = json_encode($mixJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
if (!is_string($strRaw)) {
return '(json_encode a échoué)';
}
if (strlen($strRaw) > 48000) {
return substr($strRaw, 0, 48000) . "\n\n... [tronqué — " . strlen($strRaw) . ' octets au total]';
}
return $strRaw;
}
function fxChronotrackApiRunEventDiagnostic($intCtEventId) {
$intCtEventId = intval($intCtEventId);
if ($intCtEventId <= 0) {
return array('state' => 'error', 'message' => 'ct_event_id manquant');
}
if (!fxChronotrackApiSettingsConfigured()) {
return array('state' => 'error', 'message' => fxChronotrackApiSettingsErrorMessage());
}
$arrToken = fxChronotrackApiOAuthFetchToken(false);
if ($arrToken['state'] !== 'ok') {
return array('state' => 'error', 'message' => 'OAuth : ' . ($arrToken['message'] ?? 'échec'));
}
$arrPaths = array(
array('path' => 'event/' . $intCtEventId . '/race'),
array('path' => 'event/' . $intCtEventId . '/entry', 'query' => array('page' => 1, 'page_size' => 5)),
array('path' => 'event/' . $intCtEventId),
array('path' => 'event/' . $intCtEventId . '/reg_choice'),
);
$arrProbes = array();
foreach ($arrPaths as $arrPathDef) {
$strPath = $arrPathDef['path'];
$arrQuery = isset($arrPathDef['query']) ? $arrPathDef['query'] : array();
$arrApi = fxChronotrackApiOAuthApiGet($strPath, $arrQuery);
$arrProbe = array(
'path' => $strPath,
'query' => $arrQuery,
'state' => $arrApi['state'] ?? 'error',
'http_code' => intval($arrApi['http_code'] ?? $arrApi['http']['http_code'] ?? 0),
'message' => $arrApi['message'] ?? '',
'summary' => array(),
'raw_json' => '',
);
if ($arrApi['state'] === 'ok') {
if (strpos($strPath, '/entry') !== false) {
$arrProbe['summary'] = fxChronotrackApiDiagnosticSummarizeEntryPayload($arrApi['json']);
} else {
$arrProbe['summary'] = fxChronotrackApiDiagnosticSummarizePayload($arrApi['json']);
}
$arrProbe['raw_json'] = fxChronotrackApiDiagnosticEncodeJson($arrApi['json']);
} elseif (isset($arrApi['http']['body']) && trim((string)$arrApi['http']['body']) !== '') {
$arrProbe['raw_json'] = substr(trim((string)$arrApi['http']['body']), 0, 8000);
}
$arrProbes[] = $arrProbe;
}
return array(
'state' => 'ok',
'ct_event_id' => $intCtEventId,
'oauth' => !empty($arrToken['from_cache']) ? 'token en cache' : 'token renouvelé',
'probes' => $arrProbes,
'generated_at'=> date('c'),
);
}