fino a eventi e report prima del tipo di eventi

This commit is contained in:
2026-05-26 11:47:36 +02:00
parent 0bed099d05
commit f088dba4bf
47 changed files with 1733 additions and 6899 deletions
+10 -2
View File
@@ -192,11 +192,19 @@ class DocumentoController extends Controller
$fullPath = Storage::disk('local')->path($documento->file_path);
$mimeType = $documento->mime_type;
if (str_starts_with($mimeType, 'image/')) {
$previewableMimeTypes = [
'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',
'application/pdf',
'text/plain', 'text/html', 'text/csv',
];
if (in_array($mimeType, $previewableMimeTypes)) {
return response()->file($fullPath, ['Content-Type' => $mimeType]);
}
return response()->file($fullPath, ['Content-Type' => $mimeType]);
return response()->view('documenti.preview-fallback', [
'documento' => $documento,
])->header('X-Preview-Fallback', 'true');
}
public function destroy($documento)
+31 -1
View File
@@ -342,8 +342,11 @@ class EmailController extends Controller
public function syncEmails()
{
\Illuminate\Support\Facades\Log::info('Email sync started');
$settings = EmailSetting::getActive();
if (!$settings) {
\Illuminate\Support\Facades\Log::warning('Email sync aborted: no active email configuration');
throw new \Exception('Nessuna configurazione email attiva');
}
@@ -351,6 +354,8 @@ class EmailController extends Controller
$mailbox = $this->connectImap($settings);
\Illuminate\Support\Facades\Log::info('IMAP connection established', ['host' => $settings->imap_host]);
$folderMappings = [
'INBOX' => 'inbox',
'Sent' => 'sent',
@@ -362,11 +367,19 @@ class EmailController extends Controller
'[Gmail]/Trash' => 'trash',
];
$totalProcessed = 0;
$totalNew = 0;
foreach (array_keys($folderMappings) as $imapFolderName) {
try {
$folder = $mailbox->folders()->find($imapFolderName);
if (!$folder) continue;
if (!$folder) {
\Illuminate\Support\Facades\Log::debug('IMAP folder not found', ['folder' => $imapFolderName]);
continue;
}
\Illuminate\Support\Facades\Log::info('Processing IMAP folder', ['folder' => $imapFolderName]);
$messages = $folder->messages()
->withHeaders()
->withBody()
@@ -374,14 +387,31 @@ class EmailController extends Controller
->limit(100)
->get();
\Illuminate\Support\Facades\Log::info('Messages fetched from folder', ['folder' => $imapFolderName, 'count' => count($messages)]);
foreach ($messages as $imapMessage) {
$totalProcessed++;
$messageId = $imapMessage->messageId() ?? uniqid('msg_');
$existing = EmailMessage::where('message_id', $messageId)->first();
if ($existing) {
continue;
}
$this->processImapMessage($imapMessage, $imapFolderName);
$totalNew++;
}
} catch (\Exception $e) {
\Illuminate\Support\Facades\Log::error('Error processing IMAP folder', ['folder' => $imapFolderName, 'error' => $e->getMessage()]);
continue;
}
}
\Illuminate\Support\Facades\Log::info('Email sync completed', [
'processed' => $totalProcessed,
'new' => $totalNew,
]);
return true;
}
+160 -30
View File
@@ -67,14 +67,15 @@ class EventoController extends Controller
'giorno_settimana' => 'nullable|integer|min:0|max:6',
'giorno_mese' => 'nullable|integer|min:1|max:31',
'occorrenza_mese' => 'nullable|string|max:10',
'mesi_recorrenza' => 'nullable|string',
'mesi_recorrenza' => 'nullable|array',
'mesi_recorrenza.*' => 'integer|min:1|max:12',
'mese_annuale' => 'nullable|integer|min:1|max:12',
'ora_inizio' => 'nullable|date_format:H:i',
'data_specifica' => 'nullable|date',
'durata_minuti' => 'nullable|integer|min:1',
'descrizione' => 'nullable|string',
'note' => 'nullable|string',
'is_incontro_gruppo' => 'nullable|boolean',
'is_incontro_gruppo' => 'nullable',
'gruppi' => 'nullable|array',
'gruppi.*' => 'exists:gruppi,id',
'responsabili' => 'nullable|array',
@@ -144,14 +145,15 @@ class EventoController extends Controller
'giorno_settimana' => 'nullable|integer|min:0|max:6',
'giorno_mese' => 'nullable|integer|min:1|max:31',
'occorrenza_mese' => 'nullable|string|max:10',
'mesi_recorrenza' => 'nullable|string',
'mesi_recorrenza' => 'nullable|array',
'mesi_recorrenza.*' => 'integer|min:1|max:12',
'mese_annuale' => 'nullable|integer|min:1|max:12',
'ora_inizio' => 'nullable|date_format:H:i',
'data_specifica' => 'nullable|date',
'durata_minuti' => 'nullable|integer|min:1',
'descrizione' => 'nullable|string',
'note' => 'nullable|string',
'is_incontro_gruppo' => 'nullable|boolean',
'is_incontro_gruppo' => 'nullable',
'gruppi' => 'nullable|array',
'gruppi.*' => 'exists:gruppi,id',
'responsabili' => 'nullable|array',
@@ -237,40 +239,168 @@ class EventoController extends Controller
foreach ($eventi as $evento) {
if ($evento->tipo_recorrenza === 'singolo' || $evento->tipo_recorrenza === null) {
if ($evento->data_specifica) {
$events[] = [
'id' => $evento->id,
'title' => $evento->nome_evento,
'start' => $evento->data_specifica->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''),
'url' => $baseUrl . '/eventi/' . $evento->id,
'backgroundColor' => $this->getEventoColor($evento),
'borderColor' => $this->getEventoColor($evento),
];
$events[] = $this->buildCalendarEvent($evento, $evento->data_specifica);
}
} elseif ($evento->tipo_recorrenza === 'settimanale' && $evento->giorno_settimana !== null) {
$startDate = \Carbon\Carbon::parse($start);
$endDate = \Carbon\Carbon::parse($end);
$current = $startDate->copy();
while ($current <= $endDate) {
$nextOccurrence = $current->copy()->next($evento->giorno_settimana);
if ($nextOccurrence >= $startDate && $nextOccurrence <= $endDate) {
$events[] = [
'id' => $evento->id . '_' . $nextOccurrence->format('Ymd'),
'title' => $evento->nome_evento,
'start' => $nextOccurrence->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''),
'url' => $baseUrl . '/eventi/' . $evento->id,
'backgroundColor' => $this->getEventoColor($evento),
'borderColor' => $this->getEventoColor($evento),
];
}
$current->addWeek();
}
$events = array_merge($events, $this->generateSettimanaleEvents($evento, $start, $end, $baseUrl));
} elseif ($evento->tipo_recorrenza === 'mensile' && $evento->occorrenza_mese) {
$events = array_merge($events, $this->generateMensileEvents($evento, $start, $end, $baseUrl));
} elseif ($evento->tipo_recorrenza === 'annuale' && $evento->mese_annuale) {
$events = array_merge($events, $this->generateAnnualeEvents($evento, $start, $end, $baseUrl));
} elseif ($evento->tipo_recorrenza === 'altro' && $evento->giorno_settimana !== null) {
$events = array_merge($events, $this->generateAltroEvents($evento, $start, $end, $baseUrl));
}
}
return response()->json($events);
}
protected function buildCalendarEvent(Evento $evento, $date, ?string $baseUrl = null): array
{
if ($date instanceof \Carbon\Carbon) {
$carbon = $date;
} elseif (is_string($date)) {
$carbon = \Carbon\Carbon::parse($date);
} else {
$carbon = $date;
}
$baseUrl = $baseUrl ?? request()->getSchemeAndHttpHost();
return [
'id' => $evento->id . '_' . $carbon->format('Ymd'),
'title' => $evento->nome_evento,
'start' => $carbon->format('Y-m-d') . ($evento->ora_inizio ? 'T' . $evento->ora_inizio->format('H:i') : ''),
'url' => $baseUrl . '/eventi/' . $evento->id,
'backgroundColor' => $this->getEventoColor($evento),
'borderColor' => $this->getEventoColor($evento),
];
}
protected function generateSettimanaleEvents(Evento $evento, $start, $end, $baseUrl): array
{
$startDate = \Carbon\Carbon::parse($start);
$endDate = \Carbon\Carbon::parse($end);
$events = [];
$current = $startDate->copy()->startOfWeek();
$targetDay = $evento->giorno_settimana;
while ($current <= $endDate) {
$dayOfWeek = (int) $current->format('w');
if ($dayOfWeek === $targetDay && $current >= $startDate && $current <= $endDate) {
$events[] = $this->buildCalendarEvent($evento, $current->copy(), $baseUrl);
}
$current->addDay();
}
return $events;
}
protected function generateMensileEvents(Evento $evento, $start, $end, $baseUrl): array
{
$startDate = \Carbon\Carbon::parse($start);
$endDate = \Carbon\Carbon::parse($end);
$events = [];
$parts = explode(',', $evento->occorrenza_mese);
if (count($parts) !== 2) {
return $events;
}
$occorrenza = (int) $parts[0];
$giornoSettimana = (int) $parts[1];
$mesiSelezionati = [];
if ($evento->mesi_recorrenza) {
$mesiSelezionati = array_map('intval', explode(',', $evento->mesi_recorrenza));
}
$currentMonth = $startDate->copy()->startOfMonth();
$endMonth = $endDate->copy()->startOfMonth();
while ($currentMonth <= $endMonth) {
$monthNumber = (int) $currentMonth->format('n');
if (empty($mesiSelezionati) || in_array($monthNumber, $mesiSelezionati)) {
$occurrenceDate = $this->findNthWeekdayOfMonth($currentMonth, $occorrenza, $giornoSettimana);
if ($occurrenceDate && $occurrenceDate >= $startDate && $occurrenceDate <= $endDate) {
$events[] = $this->buildCalendarEvent($evento, $occurrenceDate, $baseUrl);
}
}
$currentMonth->addMonth();
}
return $events;
}
protected function findNthWeekdayOfMonth(\Carbon\Carbon $month, int $occurrence, int $targetDayOfWeek): ?\Carbon\Carbon
{
$firstOfMonth = $month->copy()->startOfMonth();
$firstDayOfWeek = (int) $firstOfMonth->format('w');
$daysUntilTarget = ($targetDayOfWeek - $firstDayOfWeek + 7) % 7;
$firstOccurrence = $firstOfMonth->copy()->addDays($daysUntilTarget);
$targetDate = $firstOccurrence->copy()->addWeeks($occurrence - 1);
if ((int) $targetDate->format('n') !== (int) $month->format('n')) {
return null;
}
return $targetDate;
}
protected function generateAnnualeEvents(Evento $evento, $start, $end, $baseUrl): array
{
$startDate = \Carbon\Carbon::parse($start);
$endDate = \Carbon\Carbon::parse($end);
$events = [];
$year = $startDate->year;
$endYear = $endDate->year;
while ($year <= $endYear + 1) {
$day = $evento->giorno_mese ?? 1;
$eventDate = \Carbon\Carbon::create($year, $evento->mese_annuale, $day);
$daysInMonth = $eventDate->daysInMonth;
if ($evento->giorno_mese && $evento->giorno_mese > $daysInMonth) {
$eventDate = $eventDate->endOfMonth();
}
if ($eventDate >= $startDate && $eventDate <= $endDate) {
$events[] = $this->buildCalendarEvent($evento, $eventDate, $baseUrl);
}
$year++;
}
return $events;
}
protected function generateAltroEvents(Evento $evento, $start, $end, $baseUrl): array
{
$startDate = \Carbon\Carbon::parse($start);
$endDate = \Carbon\Carbon::parse($end);
$events = [];
$current = $startDate->copy()->startOfWeek();
$targetDay = $evento->giorno_settimana;
while ($current <= $endDate) {
$dayOfWeek = (int) $current->format('w');
if ($dayOfWeek === $targetDay && $current >= $startDate && $current <= $endDate) {
$events[] = $this->buildCalendarEvent($evento, $current->copy(), $baseUrl);
}
$current->addDay();
}
return $events;
}
private function getEventoColor(Evento $evento): string
{
$colors = [
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Models\Documento;
use App\Models\Gruppo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class GruppoAvatarController extends Controller
{
public function store(Request $request, Gruppo $gruppo)
{
$this->authorizeWrite('gruppi');
$request->validate([
'avatar' => 'required|image|mimes:jpeg,png,gif,webp|max:2048',
]);
$existing = $gruppo->avatar;
if ($existing) {
if ($existing->file_path && Storage::disk('local')->exists($existing->file_path)) {
Storage::disk('local')->delete($existing->file_path);
}
$existing->delete();
}
$file = $request->file('avatar');
$path = $file->store('avatars/gruppi', 'local');
$documento = Documento::create([
'user_id' => auth()->id(),
'nome_file' => $file->getClientOriginalName(),
'file_path' => $path,
'tipologia' => 'avatar',
'visibilita' => 'gruppo',
'visibilita_target_id' => $gruppo->id,
'visibilita_target_type' => Gruppo::class,
'mime_type' => $file->getMimeType(),
'dimensione' => $file->getSize(),
]);
$gruppo->avatar()->save($documento);
return response()->json(['success' => true, 'avatar_url' => $documento->file_path]);
}
public function show(Gruppo $gruppo)
{
$this->authorizeRead('gruppi');
$avatar = $gruppo->avatar;
if (!$avatar || !$avatar->file_path || !Storage::disk('local')->exists($avatar->file_path)) {
abort(404);
}
$fullPath = Storage::disk('local')->path($avatar->file_path);
return response()->file($fullPath, ['Content-Type' => $avatar->mime_type]);
}
public function destroy(Gruppo $gruppo)
{
$this->authorizeWrite('gruppi');
$avatar = $gruppo->avatar;
if ($avatar) {
if ($avatar->file_path && Storage::disk('local')->exists($avatar->file_path)) {
Storage::disk('local')->delete($avatar->file_path);
}
$avatar->delete();
}
return response()->json(['success' => true]);
}
}
+15 -117
View File
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Models\Gruppo;
@@ -30,111 +32,7 @@ class GruppoController extends Controller
$visibleColumns = $defaultVisible;
}
$allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui'])
->orderBy('nome')
->get()
->map(function ($gruppo) {
$depth = 0;
$parent = $gruppo->parent;
while ($parent) {
$depth++;
$parent = $parent->parent;
}
$gruppo->depth = $depth;
return $gruppo;
});
if ($viewMode === 'table') {
$gruppi = $this->sortGruppiHierarchically($allGruppi);
} else {
$gruppi = $allGruppi;
}
return view('gruppi.index', compact(
'gruppi',
'allColumns',
'visibleColumns',
'viewMode',
'vista'
));
}
protected function sortGruppiHierarchically($gruppi)
{
$rootGroups = $gruppi->filter(fn($g) => $g->parent_id === null)->sortBy('nome');
$sorted = collect();
foreach ($rootGroups as $root) {
$sorted->push($root);
$this->addChildrenRecursive($root, $gruppi, $sorted);
}
return $sorted;
}
protected function addChildrenRecursive($parent, $allGruppi, &$sorted)
{
$children = $allGruppi->filter(fn($g) => $g->parent_id === $parent->id)->sortBy('nome');
foreach ($children as $child) {
$sorted->push($child);
$this->addChildrenRecursive($child, $allGruppi, $sorted);
}
}
$allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui'])
->orderBy('nome')
->get()
->map(function ($gruppo) {
$depth = 0;
$parent = $gruppo->parent;
while ($parent) {
$depth++;
$parent = $parent->parent;
}
$gruppo->depth = $depth;
return $gruppo;
});
if ($viewMode === 'table') {
$gruppi = $this->sortGruppiHierarchically($allGruppi);
} else {
$gruppi = $allGruppi;
}
return view('gruppi.index', compact(
'gruppi',
'allColumns',
'visibleColumns',
'viewMode',
'vista'
));
}
protected function sortGruppiHierarchically($gruppi)
{
$rootGroups = $gruppi->filter(fn($g) => $g->parent_id === null)->sortBy('nome');
$sorted = collect();
foreach ($rootGroups as $root) {
$sorted->push($root);
$this->addChildrenRecursive($root, $gruppi, $sorted);
}
return $sorted;
}
protected function addChildrenRecursive($parent, $allGruppi, &$sorted)
{
$children = $allGruppi->filter(fn($g) => $g->parent_id === $parent->id)->sortBy('nome');
foreach ($children as $child) {
$sorted->push($child);
$this->addChildrenRecursive($child, $allGruppi, $sorted);
}
}
$allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui'])
$allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui', 'avatar'])
->orderBy('nome')
->get()
->map(function ($gruppo) {
@@ -233,31 +131,31 @@ class GruppoController extends Controller
return redirect('/gruppi/' . $gruppo->id)->with('success', 'Gruppo creato con successo.');
}
public function show($gruppo)
public function show($id)
{
$this->authorizeRead('gruppi');
$gruppo = Gruppo::with(['parent', 'children', 'diocesi', 'individui.contatti', 'individui.documenti', 'individui' => function ($q) {
$q->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione');
}, 'eventi' => function ($q) {
}, 'avatar', 'eventi' => function ($q) {
$q->where('is_incontro_gruppo', true);
}, 'eventi.responsabili.contatti'])->findOrFail($gruppo);
}, 'eventi.responsabili.contatti'])->findOrFail($id);
return view('gruppi.show', compact('gruppo'));
}
public function edit($gruppo)
public function edit($id)
{
$this->authorizeWrite('gruppi');
$gruppo = Gruppo::with(['individui.contatti', 'individui.documenti'])->findOrFail($gruppo);
$gruppo = Gruppo::with(['individui.contatti', 'individui.documenti', 'avatar'])->findOrFail($id);
$diocesi = Diocesi::orderBy('nome')->get();
$gruppi = Gruppo::where('id', '!=', $gruppo->id)->orderBy('nome')->get();
$membri = $gruppo->individui()->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione')->orderBy('cognome')->orderBy('nome')->get();
return view('gruppi.edit', compact('gruppo', 'diocesi', 'gruppi', 'membri'));
}
public function update(Request $request, $gruppo)
public function update(Request $request, $id)
{
$this->authorizeWrite('gruppi');
$gruppo = Gruppo::findOrFail($gruppo);
$gruppo = Gruppo::findOrFail($id);
$data = $request->validate([
'nome' => 'required|string|max:255',
'descrizione' => 'nullable|string',
@@ -295,10 +193,10 @@ class GruppoController extends Controller
return redirect('/gruppi/' . $gruppo->id)->with('success', 'Gruppo aggiornato.');
}
public function destroy($gruppo)
public function destroy($id)
{
$this->authorizeDelete('gruppi');
$gruppo = Gruppo::with('children', 'individui')->findOrFail($gruppo);
$gruppo = Gruppo::with('children', 'individui')->findOrFail($id);
$hasChildren = $gruppo->children()->count() > 0;
$isSuperAdmin = auth()->user()->isSuperAdmin();
@@ -393,13 +291,13 @@ class GruppoController extends Controller
return response()->json(['success' => true, 'vista_id' => $vista->id]);
}
public function deleteVista($vista)
public function deleteVista($id)
{
$vista = \App\Models\VistaReport::where('user_id', auth()->id())
->where('id', $vista)
->where('id', $id)
->firstOrFail();
$vista->delete();
return redirect()->route('gruppi.index')->with('success', 'Vista eliminata.');
}
}
}
+41
View File
@@ -121,6 +121,47 @@ class ReportController extends Controller
return redirect()->route('report.index')->with('success', 'Report personalizzato eliminato.');
}
public function printPreview(Request $request)
{
if (!auth()->user()->canAccess('report')) {
abort(403);
}
$reportType = $request->input('report');
$customReportId = $request->input('custom_id');
if ($customReportId) {
$report = \App\Models\ReportCustom::findOrFail($customReportId);
if ($report->user_id !== auth()->id()) {
abort(403);
}
$data = $this->runCustomReport($report);
return view('report.print-preview', compact('reportType', 'data', 'report'));
}
$data = match ($reportType) {
'individui_per_genere' => $this->reportIndividuiPerGenere(),
'individui_per_eta' => $this->reportIndividuiPerEta(),
'gruppi_gerarchia' => $this->reportGruppiGerarchia(),
'gruppi_membri' => $this->reportGruppiMembri(),
'eventi_calendario' => $this->reportEventiCalendario(),
'documenti_per_tipo' => $this->reportDocumentiPerTipo(),
'contatti_per_tipo' => $this->reportContattiPerTipo(),
'mailing_list_dettaglio' => $this->reportMailingListDettaglio(),
'individui_senza_contatti' => $this->reportIndividuiSenzaContatti(),
'individui_senza_gruppo' => $this->reportIndividuiSenzaGruppo(),
'eventi_per_gruppo' => $this->reportEventiPerGruppo(),
'documenti_orfani' => $this->reportDocumentiOrfani(),
default => null,
};
if (!$data) {
return redirect()->route('report.index')->with('error', 'Report non trovato.');
}
return view('report.print-preview', compact('reportType', 'data'));
}
public function exportCSV(Request $request)
{
if (!auth()->user()->canAccess('report')) {
+25 -3
View File
@@ -127,7 +127,15 @@ class Evento extends Model
public function getOccorrenzeMensiliList(): array
{
$giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica'];
$giorni = [
0 => 'Domenica',
1 => 'Lunedì',
2 => 'Martedì',
3 => 'Mercoledì',
4 => 'Giovedì',
5 => 'Venerdì',
6 => 'Sabato',
];
$list = [];
for ($occ = 1; $occ <= 4; $occ++) {
foreach ($giorni as $idx => $giorno) {
@@ -153,7 +161,15 @@ class Evento extends Model
$occorrenza = (int) $parts[0];
$giorno = (int) $parts[1];
$giorni = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica'];
$giorni = [
0 => 'Domenica',
1 => 'Lunedì',
2 => 'Martedì',
3 => 'Mercoledì',
4 => 'Giovedì',
5 => 'Venerdì',
6 => 'Sabato',
];
return $occorrenza . '° ' . ($giorni[$giorno] ?? '-');
}
@@ -199,7 +215,13 @@ class Evento extends Model
}
$mesiLabels = $this->getMesiList();
return $mesiLabels[$this->mese_annuale]['label'] ?? '-';
$label = $mesiLabels[$this->mese_annuale]['label'] ?? '-';
if ($this->giorno_mese) {
$label .= ' (giorno ' . $this->giorno_mese . ')';
}
return $label;
}
public function getPeriodicitaLabelAttribute(): string
+36 -12
View File
@@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Gruppo extends Model
@@ -48,24 +49,47 @@ class Gruppo extends Model
->withTimestamps();
}
public function avatar(): HasOne
{
return $this->hasOne(Documento::class, 'visibilita_target_id')
->where('tipologia', 'avatar')
->where('visibilita_target_type', self::class);
}
public function getAvatarUrlAttribute(): ?string
{
if ($this->avatar && $this->avatar->file_path) {
return url('/gruppi/' . $this->id . '/avatar-file');
}
return null;
}
public function getResponsabili()
{
if (empty($this->responsabile_ids)) {
return collect();
}
$ids = is_array($this->responsabile_ids)
? $this->responsabile_ids
: json_decode($this->responsabile_ids, true);
if (empty($ids)) {
return collect();
}
return Individuo::whereIn('id', $ids)->get();
}
public function getResponsabiliIds(): array
{
if (empty($this->responsabile_ids)) {
return [];
}
if (is_array($this->responsabile_ids)) {
return $this->responsabile_ids;
}
return json_decode($this->responsabile_ids, true) ?? [];
}
public function getResponsabili(): \Illuminate\Database\Eloquent\Collection
{
$ids = $this->getResponsabiliIds();
if (empty($ids)) {
return new \Illuminate\Database\Eloquent\Collection();
}
return Individuo::whereIn('id', $ids)->get();
return is_array($this->responsabile_ids)
? $this->responsabile_ids
: json_decode($this->responsabile_ids, true) ?? [];
}
public function eventi(): BelongsToMany