'Unauthorized']); exit; } header('Content-Type: application/json'); ini_set('display_errors', '0'); $q = mb_strtolower(trim($_GET['q'] ?? '')); $id = isset($_GET['id']) ? intval($_GET['id']) : null; $limit = max(1, min(50, intval($_GET['limit'] ?? 20))); $macro = trim($_GET['macro'] ?? ''); $cacheFile = __DIR__ . '/cache/matrici.json'; if (!file_exists($cacheFile)) { // Trigger cache creation require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; require_once __DIR__ . '/class/VisualLimsApiClient.class.php'; $api = VisualLimsApiClient::getInstance(); $data = $api->get('Matrice'); $matrici = []; foreach (($data['value'] ?? []) as $item) { $nome = $item['NomeMatrice'] ?? ''; if ($nome !== '' && substr($nome, 0, 1) !== '*') { $matrici[] = ['IdMatrice' => $item['IdMatrice'], 'NomeMatrice' => $nome, 'MacroMatrice' => $item['MacroMatrice'] ?? null]; } } usort($matrici, fn($a, $b) => strcasecmp($a['NomeMatrice'], $b['NomeMatrice'])); if (!is_dir(__DIR__ . '/cache')) mkdir(__DIR__ . '/cache', 0777, true); file_put_contents($cacheFile, json_encode(['success' => true, 'value' => $matrici])); } else { $cached = json_decode(file_get_contents($cacheFile), true); $matrici = $cached['value'] ?? []; } // Lookup by ID if ($id !== null) { foreach ($matrici as $m) { if ((int)$m['IdMatrice'] === $id) { echo json_encode(['results' => [['id' => $m['IdMatrice'], 'text' => $m['NomeMatrice']]]]); exit; } } echo json_encode(['results' => []]); exit; } // Return unique MacroMatrice list if (isset($_GET['macro_list'])) { $macros = []; foreach ($matrici as $m) { $mv = $m['MacroMatrice'] ?? ''; if ($mv !== '' && !in_array($mv, $macros, true)) $macros[] = $mv; } sort($macros); echo json_encode(['success' => true, 'value' => $macros]); exit; } // Search (with optional MacroMatrice filter) - multi-term AND, position-independent, ranked $terms = array_values(array_filter( preg_split('/\s+/u', $q, -1, PREG_SPLIT_NO_EMPTY) )); // Nessun termine digitato: comportamento invariato (alfabetico, taglio al limite) if (empty($terms)) { $results = []; foreach ($matrici as $m) { if ($macro !== '' && ($m['MacroMatrice'] ?? '') !== $macro) continue; $results[] = ['id' => $m['IdMatrice'], 'text' => $m['NomeMatrice'] ?? '']; if (count($results) >= $limit) break; } echo json_encode(['results' => $results]); exit; } $firstTerm = $terms[0]; $scored = []; foreach ($matrici as $m) { $nome = $m['NomeMatrice'] ?? ''; if ($macro !== '' && ($m['MacroMatrice'] ?? '') !== $macro) continue; $nomeLower = mb_strtolower($nome); // AND: tutti i termini devono essere presenti (in qualsiasi posizione) $matchAll = true; foreach ($terms as $t) { if (mb_strpos($nomeLower, $t) === false) { $matchAll = false; break; } } if (!$matchAll) continue; // Punteggio di pertinenza (più basso = più rilevante, per ordinamento crescente) if ($nomeLower === $q) { $score = 0; // match esatto } elseif (mb_strpos($nomeLower, $firstTerm) === 0) { $score = 1; // il nome inizia col primo termine } elseif (preg_match('/(^|\s)' . preg_quote($firstTerm, '/') . '/u', $nomeLower)) { $score = 2; // primo termine a inizio di una parola } else { $score = 3; // termine presente ma non a inizio parola } $scored[] = ['id' => $m['IdMatrice'], 'text' => $nome, '_s' => $score, '_n' => $nomeLower]; } // Ordina per punteggio, poi alfabetico (stabile e prevedibile) usort($scored, function ($a, $b) { if ($a['_s'] !== $b['_s']) return $a['_s'] - $b['_s']; return strcmp($a['_n'], $b['_n']); }); // Taglia al limite DOPO l'ordinamento e rimuovi i campi interni $results = array_map( fn($r) => ['id' => $r['id'], 'text' => $r['text']], array_slice($scored, 0, $limit) ); echo json_encode(['results' => $results]);