currentPdfImportId = request()->query('pdf-import'); if ($this->currentPdfImportId) { $this->refreshPdfImportStatus(); } } public function convertLegacySqlToXml() { $this->validate([ 'sqlDump' => ['required', 'file', 'mimes:sql,txt'], ]); $content = file_get_contents($this->sqlDump->getRealPath()); $dataset = $this->legacySqlToDataset($content ?: ''); $xml = $this->datasetToXml($dataset, 'legacy-sql-conversion'); return response()->streamDownload(function () use ($xml) { echo $xml; }, 'termanager-conversion.xml', ['Content-Type' => 'application/xml; charset=UTF-8']); } public function importXmlIntoApp(): void { $this->importStats = []; $this->importIssues = []; $this->validate([ 'xmlImport' => ['required', 'file', 'mimes:xml,txt'], ]); $content = file_get_contents($this->xmlImport->getRealPath()); if (! $content) { $this->addError('xmlImport', 'File XML non valido.'); return; } $xml = @simplexml_load_string($content); if (! $xml) { $this->addError('xmlImport', 'Impossibile leggere il file XML.'); return; } $actorId = auth()->id() ?? User::query()->value('id'); if (! $actorId) { $this->addError('xmlImport', 'Serve almeno un utente nel sistema per importare i dati.'); return; } $stats = [ 'zone_importate' => 0, 'tipologie_importate' => 0, 'proclamatori_importati' => 0, 'anni_importati' => 0, 'campagne_importate' => 0, 'territori_importati' => 0, 'assegnazioni_importate' => 0, 'duplicate_territori' => 0, 'assegnazioni_saltate' => 0, ]; DB::transaction(function () use ($xml, $actorId, &$stats) { Assegnazione::query()->delete(); Campagna::query()->delete(); Territorio::query()->withTrashed()->forceDelete(); Proclamatore::query()->withTrashed()->forceDelete(); Tipologia::query()->delete(); Zona::query()->delete(); AnnoTeocratico::query()->delete(); Setting::query()->delete(); $settingsNode = $xml->settings; if ($settingsNode) { Setting::instance()->update([ 'congregazione_nome' => (string) ($settingsNode->congregazione_nome ?? ''), 'giorni_giacenza_da_assegnare' => (int) ($settingsNode->giorni_giacenza_da_assegnare ?? 120), 'giorni_giacenza_prioritari' => (int) ($settingsNode->giorni_giacenza_prioritari ?? 180), 'giorni_per_smarrito' => (int) ($settingsNode->giorni_per_smarrito ?? 120), 'home_limit_list' => (int) ($settingsNode->home_limit_list ?? 10), 'assignment_link_ttl_hours' => (int) ($settingsNode->assignment_link_ttl_months ?? $settingsNode->assignment_link_ttl_hours ?? 1), 'audit_retention_days' => (int) ($settingsNode->audit_retention_days ?? 730), 'setup_completed' => true, ]); } $zoneMap = []; foreach (($xml->zones->zone ?? []) as $zoneNode) { $z = Zona::create([ 'nome' => (string) $zoneNode->nome, 'attivo' => ((int) ($zoneNode->attivo ?? 1)) === 1, ]); $stats['zone_importate']++; $legacyId = (string) ($zoneNode['legacy_id'] ?? ''); if ($legacyId !== '') { $zoneMap[$legacyId] = $z->id; } } $tipologiaMap = []; foreach (($xml->tipologie->tipologia ?? []) as $tipologiaNode) { $t = Tipologia::create([ 'nome' => (string) $tipologiaNode->nome, 'attivo' => ((int) ($tipologiaNode->attivo ?? 1)) === 1, ]); $stats['tipologie_importate']++; $legacyId = (string) ($tipologiaNode['legacy_id'] ?? ''); if ($legacyId !== '') { $tipologiaMap[$legacyId] = $t->id; } } $proclamatoreMap = []; foreach (($xml->proclamatori->proclamatore ?? []) as $proclamatoreNode) { $p = Proclamatore::create([ 'nome' => (string) $proclamatoreNode->nome, 'cognome' => (string) $proclamatoreNode->cognome, 'attivo' => ((int) ($proclamatoreNode->attivo ?? 1)) === 1, ]); $stats['proclamatori_importati']++; $legacyId = (string) ($proclamatoreNode['legacy_id'] ?? ''); if ($legacyId !== '') { $proclamatoreMap[$legacyId] = $p->id; } } $annoMap = []; foreach (($xml->anni_teocratici->anno ?? []) as $annoNode) { $label = (string) $annoNode->label; $anno = AnnoTeocratico::create([ 'label' => $label, 'start_date' => (string) $annoNode->start_date, 'end_date' => (string) $annoNode->end_date, ]); $stats['anni_importati']++; $legacyId = (string) ($annoNode['legacy_id'] ?? ''); if ($legacyId !== '') { $annoMap[$legacyId] = $anno->id; } } $campagnaMap = []; foreach (($xml->campagne->campagna ?? []) as $campagnaNode) { $campagna = Campagna::create([ 'descrizione' => (string) $campagnaNode->descrizione, 'start_date' => (string) $campagnaNode->start_date, 'end_date' => (string) $campagnaNode->end_date, ]); $stats['campagne_importate']++; $legacyId = (string) ($campagnaNode['legacy_id'] ?? ''); if ($legacyId !== '') { $campagnaMap[$legacyId] = $campagna->id; } } $territorioMap = []; $territoriNumeroVisti = []; foreach (($xml->territori->territorio ?? []) as $territorioNode) { $legacyZonaId = (string) ($territorioNode->legacy_zona_id ?? ''); $legacyTipologiaId = (string) ($territorioNode->legacy_tipologia_id ?? ''); $numero = trim((string) $territorioNode->numero); $legacyId = (string) ($territorioNode['legacy_id'] ?? ''); if ($numero === '' || isset($territoriNumeroVisti[$numero])) { $stats['duplicate_territori']++; $this->pushImportIssue('territorio', $legacyId, 'Territorio duplicato o numero vuoto (numero=' . ($numero !== '' ? $numero : 'vuoto') . ')'); continue; } if (!isset($zoneMap[$legacyZonaId], $tipologiaMap[$legacyTipologiaId])) { $this->pushImportIssue('territorio', $legacyId, 'Riferimento zona/tipologia non trovato (zona=' . $legacyZonaId . ', tipologia=' . $legacyTipologiaId . ')'); continue; } $territorio = Territorio::create([ 'numero' => $numero, 'zona_id' => $zoneMap[$legacyZonaId], 'tipologia_id' => $tipologiaMap[$legacyTipologiaId], 'confini' => (string) ($territorioNode->confini ?? ''), 'note' => (string) ($territorioNode->note ?? ''), 'attivo' => ((int) ($territorioNode->attivo ?? 1)) === 1, 'prioritario' => ((int) ($territorioNode->prioritario ?? 0)) === 1, ]); $territoriNumeroVisti[$numero] = true; $stats['territori_importati']++; if ($legacyId !== '') { $territorioMap[$legacyId] = $territorio->id; } } foreach (($xml->assegnazioni->assegnazione ?? []) as $assegnazioneNode) { $legacyTerritorio = (string) ($assegnazioneNode->legacy_territorio_id ?? ''); $legacyProclamatore = (string) ($assegnazioneNode->legacy_proclamatore_id ?? ''); $legacyAnno = (string) ($assegnazioneNode->legacy_anno_id ?? ''); $legacyId = (string) ($assegnazioneNode['legacy_id'] ?? ''); $assignedAt = $this->normalizeDateForDb((string) ($assegnazioneNode->assigned_at ?? ''), false); $returnedAt = $this->normalizeDateForDb((string) ($assegnazioneNode->returned_at ?? ''), true); if (!isset($territorioMap[$legacyTerritorio], $proclamatoreMap[$legacyProclamatore], $annoMap[$legacyAnno])) { $stats['assegnazioni_saltate']++; $this->pushImportIssue('assegnazione', $legacyId, 'Riferimenti mancanti (territorio=' . $legacyTerritorio . ', proclamatore=' . $legacyProclamatore . ', anno=' . $legacyAnno . ')'); continue; } if ($assignedAt === null) { $stats['assegnazioni_saltate']++; $this->pushImportIssue('assegnazione', $legacyId, 'Data assigned_at non valida o vuota'); continue; } $legacyCampagna = (string) ($assegnazioneNode->legacy_campagna_id ?? ''); Assegnazione::create([ 'territorio_id' => $territorioMap[$legacyTerritorio], 'proclamatore_id' => $proclamatoreMap[$legacyProclamatore], 'anno_teocratico_id' => $annoMap[$legacyAnno], 'assigned_at' => $assignedAt, 'returned_at' => $returnedAt, 'counted_in_campaign' => ((int) ($assegnazioneNode->counted_in_campaign ?? 0)) === 1, 'campaign_id' => $legacyCampagna !== '' && isset($campagnaMap[$legacyCampagna]) ? $campagnaMap[$legacyCampagna] : null, 'note' => (string) ($assegnazioneNode->note ?? ''), 'created_by' => $actorId, 'returned_by' => $returnedAt !== null ? $actorId : null, ]); $stats['assegnazioni_importate']++; } }); $this->importStats = $stats; $message = 'Import XML completato con successo.'; if ($stats['duplicate_territori'] > 0 || $stats['assegnazioni_saltate'] > 0) { $message .= ' Territori duplicati saltati: ' . $stats['duplicate_territori'] . '. Assegnazioni saltate: ' . $stats['assegnazioni_saltate'] . '.'; } session()->flash('success', $message); } public function importTerritoryPdfFolder(): void { $this->validate([ 'pdfFolder' => ['required', 'array', 'min:1'], 'pdfFolder.*' => ['file', 'mimes:pdf', 'max:10240'], ]); $importId = (string) Str::uuid(); $storedFiles = []; foreach ($this->pdfFolder as $index => $file) { $originalName = $file->getClientOriginalName(); $safeName = Str::slug(pathinfo($originalName, PATHINFO_FILENAME)); $extension = strtolower($file->getClientOriginalExtension() ?: 'pdf'); $storedPath = $file->storeAs( 'bulk-territori-imports/' . $importId, str_pad((string) $index, 4, '0', STR_PAD_LEFT) . '-' . $safeName . '.' . $extension, 'local' ); $storedFiles[] = [ 'original_name' => $originalName, 'stored_path' => $storedPath, ]; } $this->pdfFolder = []; } public function refreshPdfImportStatus(): void { if (! $this->currentPdfImportId) { return; } $state = app(TerritorioPdfImportState::class)->get($this->currentPdfImportId); if (! $state) { return; } $this->pdfImportStatus = $state['status'] ?? 'idle'; $this->pdfImportStats = $state['stats'] ?? []; $this->pdfImportLogs = $state['logs'] ?? []; $this->pdfImportIssues = $state['issues'] ?? []; $this->pdfImportLogText = implode(PHP_EOL, $this->pdfImportLogs); } protected function dispatchPdfImport(string $importId, array $storedFiles, string $initialLog): void { $state = app(TerritorioPdfImportDispatcher::class) ->dispatchStoredFiles($importId, $storedFiles, auth()->id(), $initialLog); $this->currentPdfImportId = $importId; $this->pdfImportStatus = $state['status'] ?? 'queued'; $this->pdfImportStats = $state['stats'] ?? []; $this->pdfImportLogs = $state['logs'] ?? []; $this->pdfImportIssues = $state['issues'] ?? []; $this->refreshPdfImportStatus(); session()->flash('success', 'Import PDF avviato in background. I log si aggiorneranno automaticamente.'); } public function downloadImportLogPdf() { if (empty($this->importStats)) { session()->flash('error', 'Nessun log da scaricare. Esegui prima un import XML.'); return; } $stats = $this->importStats; $issues = $this->importIssues; $generatedAt = now()->format('d/m/Y H:i:s'); $html = view('pdf.import-log', compact('stats', 'issues', 'generatedAt'))->render(); return response()->streamDownload(function () use ($html) { echo Pdf::loadHTML($html) ->setPaper('a4', 'portrait') ->output(); }, 'import-log-' . now()->format('Ymd-His') . '.pdf', ['Content-Type' => 'application/pdf']); } public function exportCurrentAsXml() { $dataset = $this->currentDataset(); $xml = $this->datasetToXml($dataset, 'current-app-export'); return response()->streamDownload(function () use ($xml) { echo $xml; }, 'termanager-export.xml', ['Content-Type' => 'application/xml; charset=UTF-8']); } public function render() { return view('livewire.settings.xml-exchange'); } private function currentDataset(): array { $settings = Setting::instance(); return [ 'settings' => [ 'congregazione_nome' => (string) ($settings->congregazione_nome ?? ''), 'giorni_giacenza_da_assegnare' => (int) ($settings->giorni_giacenza_da_assegnare ?? 120), 'giorni_giacenza_prioritari' => (int) ($settings->giorni_giacenza_prioritari ?? 180), 'giorni_per_smarrito' => (int) ($settings->giorni_per_smarrito ?? 120), 'home_limit_list' => (int) ($settings->home_limit_list ?? 10), 'assignment_link_ttl_months' => (int) ($settings->assignment_link_ttl_hours ?? 1), 'audit_retention_days' => (int) ($settings->audit_retention_days ?? 730), ], 'zones' => Zona::query()->orderBy('id')->get(['id', 'nome', 'attivo'])->toArray(), 'tipologie' => Tipologia::query()->orderBy('id')->get(['id', 'nome', 'attivo'])->toArray(), 'proclamatori' => Proclamatore::query()->withTrashed()->orderBy('id')->get(['id', 'nome', 'cognome', 'attivo'])->toArray(), 'territori' => Territorio::query()->withTrashed()->orderBy('id')->get(['id', 'numero', 'zona_id', 'tipologia_id', 'confini', 'note', 'attivo', 'prioritario'])->toArray(), 'anni_teocratici' => AnnoTeocratico::query()->orderBy('id')->get(['id', 'label', 'start_date', 'end_date'])->toArray(), 'campagne' => Campagna::query()->orderBy('id')->get(['id', 'descrizione', 'start_date', 'end_date'])->toArray(), 'assegnazioni' => Assegnazione::query()->orderBy('id')->get(['id', 'territorio_id', 'proclamatore_id', 'anno_teocratico_id', 'campaign_id', 'assigned_at', 'returned_at', 'counted_in_campaign', 'note'])->toArray(), ]; } private function legacySqlToDataset(string $sql): array { $rows = $this->extractInsertRows($sql); $congregazione = $rows['congregazione'][0][1] ?? 'Congregazione'; $impostazioni = $rows['impostazioni'][0] ?? [1, 120, 10, 120]; $settings = [ 'congregazione_nome' => (string) $congregazione, 'giorni_giacenza_da_assegnare' => (int) ($impostazioni[3] ?? 120), 'giorni_giacenza_prioritari' => (int) ($impostazioni[1] ?? 180), 'giorni_per_smarrito' => (int) ($impostazioni[3] ?? 120), 'home_limit_list' => (int) ($impostazioni[2] ?? 10), 'assignment_link_ttl_months' => 1, 'audit_retention_days' => 730, ]; $zones = []; foreach (($rows['zona'] ?? []) as $r) { $zones[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'nome' => (string) ($r[1] ?? ''), 'attivo' => 1, ]; } $tipologie = []; foreach (($rows['tipologia'] ?? []) as $r) { $tipologie[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'nome' => (string) ($r[1] ?? ''), 'attivo' => 1, ]; } $proclamatori = []; foreach (($rows['proclamatore'] ?? []) as $r) { $proclamatori[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'cognome' => (string) ($r[1] ?? ''), 'nome' => (string) ($r[2] ?? ''), 'attivo' => ((int) ($r[3] ?? 1)) === 1 ? 1 : 0, ]; } $territori = []; foreach (($rows['territorio'] ?? []) as $r) { $territori[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'numero' => (string) ($r[1] ?? ''), 'legacy_tipologia_id' => (string) ($r[2] ?? ''), 'legacy_zona_id' => (string) ($r[3] ?? ''), 'confini' => (string) ($r[4] ?? ''), 'note' => (string) ($r[5] ?? ''), 'attivo' => ((int) ($r[8] ?? 1)) === 1 ? 1 : 0, 'prioritario' => ((int) ($r[11] ?? 0)) > 0 ? 1 : 0, ]; } $anni = []; foreach (($rows['annoServizio'] ?? []) as $r) { $label = (string) ($r[1] ?? ''); [$startDate, $endDate] = $this->datesFromLegacyAnnoLabel($label); $anni[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'label' => str_replace(' - ', '-', $label), 'start_date' => $startDate, 'end_date' => $endDate, ]; } $campagne = []; foreach (($rows['campagna'] ?? []) as $r) { $campagne[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'descrizione' => (string) ($r[1] ?? ''), 'start_date' => $this->toDateOnly((string) ($r[2] ?? '')), 'end_date' => $this->toDateOnly((string) ($r[3] ?? '')), ]; } $assegnazioni = []; foreach (($rows['assegnazione'] ?? []) as $r) { $assegnazioni[] = [ 'legacy_id' => (string) ($r[0] ?? ''), 'legacy_territorio_id' => (string) ($r[1] ?? ''), 'legacy_proclamatore_id' => (string) ($r[2] ?? ''), 'legacy_anno_id' => (string) ($r[9] ?? ''), 'legacy_campagna_id' => $r[8] === null ? '' : (string) $r[8], 'assigned_at' => $this->toDateOnly((string) ($r[4] ?? '')), 'returned_at' => $this->toDateOnly((string) ($r[5] ?? '')), 'counted_in_campaign' => ((int) ($r[7] ?? 0)) === 1 ? 1 : 0, 'note' => '', ]; } return [ 'settings' => $settings, 'zones' => $zones, 'tipologie' => $tipologie, 'proclamatori' => $proclamatori, 'territori' => $territori, 'anni_teocratici' => $anni, 'campagne' => $campagne, 'assegnazioni' => $assegnazioni, ]; } private function extractInsertRows(string $sql): array { $result = []; preg_match_all('/INSERT INTO `([^`]+)` VALUES\s*(.+?);/s', $sql, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $table = $match[1]; $valuesPayload = $match[2]; $tuples = $this->splitSqlTuples($valuesPayload); foreach ($tuples as $tuple) { $result[$table][] = $this->parseSqlTuple($tuple); } } return $result; } private function splitSqlTuples(string $payload): array { $tuples = []; $inString = false; $escape = false; $depth = 0; $current = ''; $len = strlen($payload); for ($i = 0; $i < $len; $i++) { $ch = $payload[$i]; if ($inString) { $current .= $ch; if ($escape) { $escape = false; continue; } if ($ch === '\\\\') { $escape = true; continue; } if ($ch === "'") { $inString = false; } continue; } if ($ch === "'") { $inString = true; $current .= $ch; continue; } if ($ch === '(') { if ($depth === 0) { $current = ''; } $depth++; continue; } if ($ch === ')') { $depth--; if ($depth === 0) { $tuples[] = $current; $current = ''; continue; } } if ($depth > 0) { $current .= $ch; } } return $tuples; } private function parseSqlTuple(string $tuple): array { $values = []; $inString = false; $escape = false; $current = ''; $len = strlen($tuple); for ($i = 0; $i < $len; $i++) { $ch = $tuple[$i]; if ($inString) { $current .= $ch; if ($escape) { $escape = false; continue; } if ($ch === '\\\\') { $escape = true; continue; } if ($ch === "'") { $inString = false; } continue; } if ($ch === "'") { $inString = true; $current .= $ch; continue; } if ($ch === ',') { $values[] = $this->normalizeSqlValue($current); $current = ''; continue; } $current .= $ch; } if ($current !== '') { $values[] = $this->normalizeSqlValue($current); } return $values; } private function normalizeSqlValue(string $raw) { $raw = trim($raw); if (strcasecmp($raw, 'NULL') === 0) { return null; } if (str_starts_with($raw, "'") && str_ends_with($raw, "'")) { $v = substr($raw, 1, -1); $v = str_replace(["\\\\", "\\'", '\\"', '\\n', '\\r', '\\t'], ['\\', "'", '"', "\n", "\r", "\t"], $v); return html_entity_decode($v, ENT_QUOTES | ENT_HTML5, 'UTF-8'); } if (is_numeric($raw)) { return str_contains($raw, '.') ? (float) $raw : (int) $raw; } return $raw; } private function datesFromLegacyAnnoLabel(string $label): array { if (preg_match('/(\d{4})\s*-\s*(\d{4})/', $label, $m)) { return [$m[1] . '-09-01', $m[2] . '-08-31']; } $now = Carbon::now(); return [$now->copy()->startOfYear()->toDateString(), $now->copy()->endOfYear()->toDateString()]; } private function toDateOnly(string $dateTime): string { if ($dateTime === '') { return ''; } return substr($dateTime, 0, 10); } private function normalizeDateForDb(string $raw, bool $nullable): ?string { $raw = trim($raw); if ($raw === '' || $raw === '0000-00-00' || $raw === '0000-00-00 00:00:00') { return $nullable ? null : null; } try { return Carbon::parse($raw)->toDateString(); } catch (\Throwable $e) { return $nullable ? null : null; } } private function pushImportIssue(string $entity, string $legacyId, string $reason): void { if (count($this->importIssues) >= 300) { return; } $this->importIssues[] = [ 'entity' => $entity, 'legacy_id' => $legacyId !== '' ? $legacyId : '-', 'reason' => $reason, ]; } private function datasetToXml(array $dataset, string $source): string { $xml = new \SimpleXMLElement(''); $xml->addAttribute('version', '1.0'); $xml->addAttribute('source', $source); $xml->addAttribute('generated_at', now()->toIso8601String()); $settings = $xml->addChild('settings'); foreach ($dataset['settings'] as $key => $value) { $settings->addChild($key, htmlspecialchars((string) $value, ENT_QUOTES | ENT_XML1, 'UTF-8')); } $zonesNode = $xml->addChild('zones'); foreach ($dataset['zones'] as $zone) { $node = $zonesNode->addChild('zone'); if (isset($zone['legacy_id'])) { $node->addAttribute('legacy_id', (string) $zone['legacy_id']); } $node->addChild('nome', htmlspecialchars((string) ($zone['nome'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('attivo', (string) ((int) ($zone['attivo'] ?? 1))); } $tipologieNode = $xml->addChild('tipologie'); foreach ($dataset['tipologie'] as $tipologia) { $node = $tipologieNode->addChild('tipologia'); if (isset($tipologia['legacy_id'])) { $node->addAttribute('legacy_id', (string) $tipologia['legacy_id']); } $node->addChild('nome', htmlspecialchars((string) ($tipologia['nome'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('attivo', (string) ((int) ($tipologia['attivo'] ?? 1))); } $proclamatoriNode = $xml->addChild('proclamatori'); foreach ($dataset['proclamatori'] as $proclamatore) { $node = $proclamatoriNode->addChild('proclamatore'); if (isset($proclamatore['legacy_id'])) { $node->addAttribute('legacy_id', (string) $proclamatore['legacy_id']); } $node->addChild('nome', htmlspecialchars((string) ($proclamatore['nome'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('cognome', htmlspecialchars((string) ($proclamatore['cognome'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('attivo', (string) ((int) ($proclamatore['attivo'] ?? 1))); } $territoriNode = $xml->addChild('territori'); foreach ($dataset['territori'] as $territorio) { $node = $territoriNode->addChild('territorio'); if (isset($territorio['legacy_id'])) { $node->addAttribute('legacy_id', (string) $territorio['legacy_id']); } $node->addChild('numero', htmlspecialchars((string) ($territorio['numero'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('legacy_zona_id', (string) ($territorio['legacy_zona_id'] ?? ($territorio['zona_id'] ?? ''))); $node->addChild('legacy_tipologia_id', (string) ($territorio['legacy_tipologia_id'] ?? ($territorio['tipologia_id'] ?? ''))); $node->addChild('confini', htmlspecialchars((string) ($territorio['confini'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('note', htmlspecialchars((string) ($territorio['note'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('attivo', (string) ((int) ($territorio['attivo'] ?? 1))); $node->addChild('prioritario', (string) ((int) ($territorio['prioritario'] ?? 0))); } $anniNode = $xml->addChild('anni_teocratici'); foreach ($dataset['anni_teocratici'] as $anno) { $node = $anniNode->addChild('anno'); if (isset($anno['legacy_id'])) { $node->addAttribute('legacy_id', (string) $anno['legacy_id']); } $node->addChild('label', htmlspecialchars((string) ($anno['label'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('start_date', (string) ($anno['start_date'] ?? '')); $node->addChild('end_date', (string) ($anno['end_date'] ?? '')); } $campagneNode = $xml->addChild('campagne'); foreach ($dataset['campagne'] as $campagna) { $node = $campagneNode->addChild('campagna'); if (isset($campagna['legacy_id'])) { $node->addAttribute('legacy_id', (string) $campagna['legacy_id']); } $node->addChild('descrizione', htmlspecialchars((string) ($campagna['descrizione'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); $node->addChild('start_date', (string) ($campagna['start_date'] ?? '')); $node->addChild('end_date', (string) ($campagna['end_date'] ?? '')); } $assegnazioniNode = $xml->addChild('assegnazioni'); foreach ($dataset['assegnazioni'] as $assegnazione) { $node = $assegnazioniNode->addChild('assegnazione'); if (isset($assegnazione['legacy_id'])) { $node->addAttribute('legacy_id', (string) $assegnazione['legacy_id']); } $node->addChild('legacy_territorio_id', (string) ($assegnazione['legacy_territorio_id'] ?? ($assegnazione['territorio_id'] ?? ''))); $node->addChild('legacy_proclamatore_id', (string) ($assegnazione['legacy_proclamatore_id'] ?? ($assegnazione['proclamatore_id'] ?? ''))); $node->addChild('legacy_anno_id', (string) ($assegnazione['legacy_anno_id'] ?? ($assegnazione['anno_teocratico_id'] ?? ''))); $node->addChild('legacy_campagna_id', (string) ($assegnazione['legacy_campagna_id'] ?? ($assegnazione['campaign_id'] ?? ''))); $node->addChild('assigned_at', (string) ($assegnazione['assigned_at'] ?? '')); $node->addChild('returned_at', (string) ($assegnazione['returned_at'] ?? '')); $node->addChild('counted_in_campaign', (string) ((int) ($assegnazione['counted_in_campaign'] ?? 0))); $node->addChild('note', htmlspecialchars((string) ($assegnazione['note'] ?? ''), ENT_QUOTES | ENT_XML1, 'UTF-8')); } return $xml->asXML() ?: ''; } }