v.Version)` collisionnait * silencieusement, ce qui faisait apparaître dans l'UI le mauvais ZIP * pour un user firefighter. * * @param array> $versions * @return list> */ private static function filterVersions(array $versions, ?string $clientChannel): array { // Étape 1 : filter visible par ce client $visible = []; foreach ($versions as $v) { $channels = (isset($v['channels']) && is_array($v['channels']) && !empty($v['channels'])) ? $v['channels'] : ['default']; $isPublic = in_array('default', $channels, true); $matchesUser = $clientChannel !== null && in_array($clientChannel, $channels, true); if ($isPublic || $matchesUser) { $visible[] = ['entry' => $v, 'channels' => $channels]; } } // Étape 2 : group by version, pick most specific per group $byVersion = []; foreach ($visible as $item) { $key = (string)($item['entry']['version'] ?? '?'); $byVersion[$key][] = $item; } $result = []; foreach ($byVersion as $items) { if (count($items) === 1) { $result[] = $items[0]['entry']; continue; } // Plusieurs entries pour ce numéro : on cherche d'abord une qui // matche le channel spécifique du client (firefighter, police…), // sinon on retombe sur l'entry default. $specific = null; $defaultEntry = null; foreach ($items as $item) { if ($clientChannel !== null && $specific === null && in_array($clientChannel, $item['channels'], true)) { $specific = $item; } if ($defaultEntry === null && in_array('default', $item['channels'], true)) { $defaultEntry = $item; } } $picked = $specific ?? $defaultEntry ?? $items[0]; $result[] = $picked['entry']; } return array_values($result); } }