validate( ['kmlFile' => 'required|file|max:10240'], [], ['kmlFile' => 'file KML'], ); $estensione = strtolower($this->kmlFile->getClientOriginalExtension()); if (! in_array($estensione, ['kml', 'xml'], true)) { $this->addError('kmlFile', 'Il file deve essere un .kml (o .xml in formato KML).'); return; } try { $quante = $area->salvaKml( file_get_contents($this->kmlFile->getRealPath()), $this->kmlFile->getClientOriginalName(), ); } catch (\Throwable $e) { $this->addError('kmlFile', $e->getMessage()); return; } $this->kmlFile = null; activity()->causedBy(auth()->user())->log('piantine_kml_caricato'); session()->flash('success', "Area della città aggiornata: {$quante} geometrie riconosciute nel KML."); } // ─── Generazione ──────────────────────────────────────────────────────── public function generaImmagine(int $mappaId, PiantinaRenderer $renderer) { $mappa = TerritorioMappa::with('territorio')->findOrFail($mappaId); try { $renderer->render($mappa); } catch (\Throwable $e) { session()->flash('error', $e->getMessage()); return; } session()->flash('success', "Immagine generata per {$mappa->etichetta()}."); } public function generaPdf(int $mappaId, PiantinaPdfService $pdfService) { $mappa = TerritorioMappa::with('territorio')->findOrFail($mappaId); if (! $mappa->collegata()) { session()->flash('error', 'Questa piantina non è collegata a nessun territorio: collegala prima di generare il PDF.'); return; } try { $pdfService->sostituisci($mappa->territorio, $mappa); } catch (\Throwable $e) { session()->flash('error', $e->getMessage()); return; } session()->flash('success', "PDF del territorio {$mappa->territorio->numero} sostituito. Il precedente è nello storico versioni."); } // ─── Collegamento al territorio ───────────────────────────────────────── public function apriCollegamento(int $mappaId): void { $this->collegamentoAperto = $mappaId; $this->territorioDaCollegare = TerritorioMappa::find($mappaId)?->territorio_id; } public function chiudiCollegamento(): void { $this->collegamentoAperto = null; $this->territorioDaCollegare = null; } public function collega(int $mappaId) { $mappa = TerritorioMappa::findOrFail($mappaId); if (! $this->territorioDaCollegare) { session()->flash('error', 'Scegli il territorio a cui collegare la piantina.'); return; } $territorio = Territorio::findOrFail($this->territorioDaCollegare); // Un territorio ha una piantina sola: se ne aveva già un'altra il // vincolo di unicità la respingerebbe con un errore di database, che // non spiega niente a chi sta guardando la pagina. $occupato = TerritorioMappa::where('territorio_id', $territorio->id) ->where('id', '!=', $mappa->id) ->exists(); if ($occupato) { session()->flash('error', "Il territorio {$territorio->numero} ha già una piantina: scollegala prima di assegnargli questa."); return; } $mappa->update(['territorio_id' => $territorio->id]); $this->chiudiCollegamento(); activity()->causedBy(auth()->user())->performedOn($territorio)->log('piantina_collegata'); session()->flash('success', "Piantina collegata al territorio {$territorio->numero}."); } public function scollega(int $mappaId) { $mappa = TerritorioMappa::with('territorio')->findOrFail($mappaId); $numero = $mappa->territorio?->numero ?? '?'; // Senza territorio serve un'etichetta, altrimenti la piantina sparisce // dall'elenco sotto un anonimo "Piantina #12". $mappa->update([ 'territorio_id' => null, 'nome' => $mappa->nome ?: "Ex territorio {$numero}", ]); session()->flash('success', "Piantina scollegata dal territorio {$numero}. Il PDF del territorio resta com'è."); } public function eliminaPiantina(int $mappaId) { $mappa = TerritorioMappa::with('territorio')->findOrFail($mappaId); $etichetta = $mappa->etichetta(); if ($mappa->image_path) { Storage::disk('public')->delete($mappa->image_path); } $mappa->delete(); session()->flash('success', "{$etichetta}: poligono e immagine eliminati. Il PDF del territorio resta com'è."); } // ─── Storico versioni ─────────────────────────────────────────────────── public function ripristinaVersione(int $versioneId, PiantinaPdfService $pdfService) { $versione = TerritorioPdfVersione::with('territorio')->findOrFail($versioneId); $numero = $versione->territorio?->numero ?? '?'; try { $pdfService->ripristina($versione); } catch (\Throwable $e) { session()->flash('error', $e->getMessage()); return; } session()->flash('success', "Versione precedente ripristinata per il territorio {$numero}."); } public function eliminaVersione(int $versioneId) { $versione = TerritorioPdfVersione::findOrFail($versioneId); if (Storage::disk('public')->exists($versione->pdf_path)) { Storage::disk('public')->delete($versione->pdf_path); } $versione->delete(); session()->flash('success', 'Versione eliminata definitivamente.'); } public function render(PiantineArea $area) { return view('livewire.piantine.piantine-manager', [ 'config' => $area->config(), 'piantine' => TerritorioMappa::with('territorio') ->get() ->sortBy(fn ($m) => [ $m->collegata() ? 0 : 1, strlen((string) $m->territorio?->numero), (string) $m->territorio?->numero, (string) $m->nome, ]) ->values(), 'territori' => Territorio::attivi() ->orderByRaw('LENGTH(numero), numero') ->get(['id', 'numero']), 'versioni' => TerritorioPdfVersione::with('territorio') ->orderByDesc('sostituito_il') ->limit(30) ->get(), 'title' => 'Piantine dei territori', ]); } }