180 lines
6.7 KiB
PHP
180 lines
6.7 KiB
PHP
<?php
|
|
namespace App\Support\Livewire;
|
|
|
|
use App\Models\RubricaUniversale;
|
|
use BackedEnum;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Str;
|
|
|
|
trait SupportsRubricaLookup
|
|
{
|
|
/**
|
|
* Normalizza input Livewire eterogenei in una stringa di ricerca stabile.
|
|
*/
|
|
protected function normalizeRubricaLookupText($value): string
|
|
{
|
|
if (is_array($value)) {
|
|
$value = Arr::first(Arr::flatten($value));
|
|
}
|
|
|
|
if ($value instanceof BackedEnum) {
|
|
$value = $value->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<string,mixed>
|
|
*/
|
|
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 ?? ''),
|
|
'cf' => trim((string) ($rubrica->codice_fiscale ?? '')),
|
|
'piva' => trim((string) ($rubrica->partita_iva ?? '')),
|
|
'note' => Str::limit(trim((string) ($rubrica->note ?? '')), 100),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Ricerca libera su rubrica con deduplica label e fallback sulla selezione corrente.
|
|
*
|
|
* @param array<int,string>|null $categories
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
protected function searchRubricaLookupMatches(string $raw, ?int $selectedId = null, ?array $categories = null, int $limit = 12, ?int $amministratoreId = null): 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) ?: '';
|
|
$rows = [];
|
|
|
|
$query = RubricaUniversale::query()
|
|
->whereNull('deleted_at')
|
|
->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])
|
|
->orWhereRaw("LOWER(COALESCE(codice_fiscale, '')) LIKE ?", [$needle])
|
|
->orWhereRaw("LOWER(COALESCE(partita_iva, '')) 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 . '%'])
|
|
->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . $digits . '%']);
|
|
}
|
|
})
|
|
->orderByRaw('CASE WHEN id = ? THEN 0 ELSE 1 END', [(int) ($selectedId ?? 0)])
|
|
->orderBy('ragione_sociale')
|
|
->orderBy('cognome')
|
|
->orderBy('nome')
|
|
->limit(80);
|
|
|
|
if ($categories !== null && $categories !== []) {
|
|
$query->whereIn('categoria', $categories);
|
|
}
|
|
|
|
if ($amministratoreId !== null && $amministratoreId > 0 && method_exists(new RubricaUniversale(), 'getTable')) {
|
|
$query->where(function ($builder) use ($amministratoreId): void {
|
|
$builder->where('amministratore_id', $amministratoreId)
|
|
->orWhereNull('amministratore_id');
|
|
});
|
|
}
|
|
|
|
$matches = $query->get();
|
|
|
|
foreach ($matches as $rubrica) {
|
|
$row = $this->mapRubricaLookupRow($rubrica);
|
|
$row['score'] = $this->scoreRubricaLookupMatch($row, $raw, $digits, $selectedId);
|
|
$rows[] = $row;
|
|
}
|
|
|
|
usort($rows, fn(array $left, array $right): int => ((int) $right['score']) <=> ((int) $left['score']));
|
|
|
|
$rows = array_values(array_slice(array_map(function (array $row): array {
|
|
unset($row['score']);
|
|
|
|
return $row;
|
|
}, $rows), 0, $limit));
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $row
|
|
*/
|
|
protected function scoreRubricaLookupMatch(array $row, string $raw, string $digits, ?int $selectedId = null): int
|
|
{
|
|
$score = (int) (($selectedId ?? 0) > 0 && (int) ($row['id'] ?? 0) === (int) $selectedId ? 1000 : 0);
|
|
|
|
$haystack = mb_strtolower(implode(' ', array_filter([
|
|
(string) ($row['label'] ?? ''),
|
|
(string) ($row['email'] ?? ''),
|
|
(string) ($row['phone'] ?? ''),
|
|
(string) ($row['cf'] ?? ''),
|
|
(string) ($row['piva'] ?? ''),
|
|
(string) ($row['category'] ?? ''),
|
|
(string) ($row['note'] ?? ''),
|
|
])));
|
|
|
|
if ($raw !== '' && str_contains($haystack, mb_strtolower($raw))) {
|
|
$score += 90;
|
|
}
|
|
|
|
if ($digits !== '') {
|
|
$phoneDigits = preg_replace('/\D+/', '', (string) ($row['phone'] ?? '')) ?: '';
|
|
if ($phoneDigits !== '' && str_contains($phoneDigits, $digits)) {
|
|
$score += 70;
|
|
}
|
|
}
|
|
|
|
return $score;
|
|
}
|
|
}
|