value; } if (! is_scalar($value) && $value !== null) { return ''; } return trim((string) ($value ?? '')); } protected function normalizeRubricaLookupId($value): ?int { $normalized = $this->normalizeRubricaLookupText($value); if ($normalized === '' || ! is_numeric($normalized)) { return null; } $id = (int) $normalized; return $id > 0 ? $id : null; } protected function formatRubricaLookupLabel(?RubricaUniversale $rubrica): string { if (! $rubrica instanceof RubricaUniversale) { return ''; } $label = trim((string) ($rubrica->ragione_sociale ?: $rubrica->nome_completo)); return $label !== '' ? $label : ('Rubrica #' . (int) $rubrica->id); } /** * Mappa una riga rubrica in un payload leggero e riusabile nelle dropdown live. * * @return array */ protected function mapRubricaLookupRow(RubricaUniversale $rubrica): array { $phone = trim((string) ($rubrica->telefono_ufficio ?: $rubrica->telefono_cellulare ?: $rubrica->telefono_casa)); return [ 'id' => (int) $rubrica->id, 'label' => $this->formatRubricaLookupLabel($rubrica), 'email' => trim((string) ($rubrica->email ?? '')), 'phone' => $phone, 'category' => (string) ($rubrica->categoria ?? ''), 'note' => Str::limit(trim((string) ($rubrica->note ?? '')), 100), ]; } /** * Ricerca libera su rubrica con deduplica label e fallback sulla selezione corrente. * * @param array $categories * @return array> */ protected function searchRubricaLookupMatches(string $raw, ?int $selectedId = null, array $categories = ['assicurazione', 'fornitore', 'altro'], int $limit = 12): array { $raw = $this->normalizeRubricaLookupText($raw); if ($raw === '') { if (($selectedId ?? 0) > 0) { $selected = RubricaUniversale::query()->find($selectedId); return $selected instanceof RubricaUniversale ? [$this->mapRubricaLookupRow($selected)] : []; } return []; } $needle = '%' . mb_strtolower($raw) . '%'; $digits = preg_replace('/\D+/', '', $raw) ?: ''; $seen = []; $rows = []; $matches = RubricaUniversale::query() ->whereNull('deleted_at') ->whereIn('categoria', $categories) ->where(function ($query) use ($needle, $digits): void { $query->whereRaw("LOWER(COALESCE(ragione_sociale, '')) LIKE ?", [$needle]) ->orWhereRaw("LOWER(COALESCE(nome, '')) LIKE ?", [$needle]) ->orWhereRaw("LOWER(COALESCE(cognome, '')) LIKE ?", [$needle]) ->orWhereRaw("LOWER(COALESCE(email, '')) LIKE ?", [$needle]) ->orWhereRaw("LOWER(COALESCE(note, '')) LIKE ?", [$needle]); if ($digits !== '') { $query->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . $digits . '%']) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . $digits . '%']); } }) ->orderBy('ragione_sociale') ->orderBy('cognome') ->orderBy('nome') ->limit(80) ->get(); foreach ($matches as $rubrica) { $row = $this->mapRubricaLookupRow($rubrica); $key = mb_strtolower(trim((string) $row['label'])); if ($key === '' || isset($seen[$key])) { continue; } $seen[$key] = true; $rows[] = $row; if (count($rows) >= $limit) { break; } } return $rows; } }