986 lines
34 KiB
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'),
|
|
);
|
|
}
|