++ fix import e permessi
This commit is contained in:
@@ -181,6 +181,7 @@ class XmlExchange extends Component
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'utenti_importati' => 0,
|
||||
'zone_importate' => 0,
|
||||
'tipologie_importate' => 0,
|
||||
'proclamatori_importati' => 0,
|
||||
@@ -212,22 +213,96 @@ class XmlExchange extends Component
|
||||
if ($settingsNode) {
|
||||
Setting::instance()->update([
|
||||
'congregazione_nome' => (string) ($settingsNode->congregazione_nome ?? ''),
|
||||
'public_base_url' => (string) ($settingsNode->public_base_url ?? ''),
|
||||
'logo_path' => (string) ($settingsNode->logo_path ?? ''),
|
||||
'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),
|
||||
'pdf_viewer_show_download' => ((int) ($settingsNode->pdf_viewer_show_download ?? 0)) === 1,
|
||||
'audit_retention_days' => (int) ($settingsNode->audit_retention_days ?? 730),
|
||||
// The first-run wizard was removed; an imported dataset always
|
||||
// represents a configured install, so setup is complete.
|
||||
'setup_completed' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
// Users are UPSERTED by email, never wiped. Deleting the users
|
||||
// table during a restore risks locking out the administrator
|
||||
// performing the import (e.g. a backup that predates their account,
|
||||
// or a partial file). Existing accounts are updated in place;
|
||||
// accounts in the file are (re)created. $userMap remaps the
|
||||
// created_by/returned_by FKs on the assignments below.
|
||||
$userMap = [];
|
||||
foreach (($xml->users->user ?? []) as $userNode) {
|
||||
$email = trim((string) ($userNode->email ?? ''));
|
||||
$legacyId = (string) ($userNode['legacy_id'] ?? '');
|
||||
|
||||
if ($email === '') {
|
||||
$this->pushImportIssue('utente', $legacyId, 'Email mancante');
|
||||
continue;
|
||||
}
|
||||
|
||||
$user = User::query()->firstOrNew(['email' => $email]);
|
||||
$user->name = (string) ($userNode->name ?? $email);
|
||||
if (! $user->exists) {
|
||||
// password is NOT NULL; the real hash is written raw below.
|
||||
$user->password = Str::password(24);
|
||||
}
|
||||
$user->save();
|
||||
|
||||
// Ensure every referenced role exists before syncing — the
|
||||
// standard three come from the seeder, but a custom role in the
|
||||
// backup would otherwise make syncRoles() throw.
|
||||
$roleNames = [];
|
||||
foreach (($userNode->roles->role ?? []) as $roleNode) {
|
||||
$roleName = trim((string) $roleNode);
|
||||
if ($roleName !== '') {
|
||||
\Spatie\Permission\Models\Role::firstOrCreate(['name' => $roleName, 'guard_name' => 'web']);
|
||||
$roleNames[] = $roleName;
|
||||
}
|
||||
}
|
||||
$user->syncRoles($roleNames);
|
||||
|
||||
// Password hash, remember_token, verification flag and
|
||||
// timestamps are written with the query builder: the raw stored
|
||||
// hash is preserved exactly (the 'hashed' cast would re-validate
|
||||
// the bcrypt cost and could reject a hash made with a different
|
||||
// BCRYPT_ROUNDS), and Eloquent does not stamp its own timestamps.
|
||||
$meta = [];
|
||||
$passwordHash = (string) ($userNode->password ?? '');
|
||||
if ($passwordHash !== '') {
|
||||
$meta['password'] = $passwordHash;
|
||||
}
|
||||
$rememberToken = (string) ($userNode->remember_token ?? '');
|
||||
$meta['remember_token'] = $rememberToken !== '' ? $rememberToken : null;
|
||||
$meta['email_verified_at'] = $this->normalizeDateTimeForDb((string) ($userNode->email_verified_at ?? ''));
|
||||
|
||||
$createdAt = $this->normalizeDateTimeForDb((string) ($userNode->created_at ?? ''));
|
||||
if ($createdAt !== null) {
|
||||
$meta['created_at'] = $createdAt;
|
||||
}
|
||||
$updatedAt = $this->normalizeDateTimeForDb((string) ($userNode->updated_at ?? ''));
|
||||
if ($updatedAt !== null) {
|
||||
$meta['updated_at'] = $updatedAt;
|
||||
}
|
||||
|
||||
DB::table('users')->where('id', $user->id)->update($meta);
|
||||
|
||||
$stats['utenti_importati']++;
|
||||
if ($legacyId !== '') {
|
||||
$userMap[$legacyId] = $user->id;
|
||||
}
|
||||
}
|
||||
|
||||
$zoneMap = [];
|
||||
foreach (($xml->zones->zone ?? []) as $zoneNode) {
|
||||
$z = Zona::create([
|
||||
'nome' => (string) $zoneNode->nome,
|
||||
'attivo' => ((int) ($zoneNode->attivo ?? 1)) === 1,
|
||||
]);
|
||||
$this->applyRowMeta('zone', $z->id, $zoneNode);
|
||||
$stats['zone_importate']++;
|
||||
$legacyId = (string) ($zoneNode['legacy_id'] ?? '');
|
||||
if ($legacyId !== '') {
|
||||
@@ -241,6 +316,7 @@ class XmlExchange extends Component
|
||||
'nome' => (string) $tipologiaNode->nome,
|
||||
'attivo' => ((int) ($tipologiaNode->attivo ?? 1)) === 1,
|
||||
]);
|
||||
$this->applyRowMeta('tipologie', $t->id, $tipologiaNode);
|
||||
$stats['tipologie_importate']++;
|
||||
$legacyId = (string) ($tipologiaNode['legacy_id'] ?? '');
|
||||
if ($legacyId !== '') {
|
||||
@@ -255,6 +331,7 @@ class XmlExchange extends Component
|
||||
'cognome' => (string) $proclamatoreNode->cognome,
|
||||
'attivo' => ((int) ($proclamatoreNode->attivo ?? 1)) === 1,
|
||||
]);
|
||||
$this->applyRowMeta('proclamatori', $p->id, $proclamatoreNode, true);
|
||||
$stats['proclamatori_importati']++;
|
||||
$legacyId = (string) ($proclamatoreNode['legacy_id'] ?? '');
|
||||
if ($legacyId !== '') {
|
||||
@@ -270,6 +347,7 @@ class XmlExchange extends Component
|
||||
'start_date' => (string) $annoNode->start_date,
|
||||
'end_date' => (string) $annoNode->end_date,
|
||||
]);
|
||||
$this->applyRowMeta('anni_teocratici', $anno->id, $annoNode);
|
||||
$stats['anni_importati']++;
|
||||
$legacyId = (string) ($annoNode['legacy_id'] ?? '');
|
||||
if ($legacyId !== '') {
|
||||
@@ -284,6 +362,7 @@ class XmlExchange extends Component
|
||||
'start_date' => (string) $campagnaNode->start_date,
|
||||
'end_date' => (string) $campagnaNode->end_date,
|
||||
]);
|
||||
$this->applyRowMeta('campagne', $campagna->id, $campagnaNode);
|
||||
$stats['campagne_importate']++;
|
||||
$legacyId = (string) ($campagnaNode['legacy_id'] ?? '');
|
||||
if ($legacyId !== '') {
|
||||
@@ -310,6 +389,9 @@ class XmlExchange extends Component
|
||||
continue;
|
||||
}
|
||||
|
||||
$pdfPath = (string) ($territorioNode->pdf_path ?? '');
|
||||
$thumbnailPath = (string) ($territorioNode->thumbnail_path ?? '');
|
||||
|
||||
$territorio = Territorio::create([
|
||||
'numero' => $numero,
|
||||
'zona_id' => $zoneMap[$legacyZonaId],
|
||||
@@ -318,7 +400,10 @@ class XmlExchange extends Component
|
||||
'note' => (string) ($territorioNode->note ?? ''),
|
||||
'attivo' => ((int) ($territorioNode->attivo ?? 1)) === 1,
|
||||
'prioritario' => ((int) ($territorioNode->prioritario ?? 0)) === 1,
|
||||
'pdf_path' => $pdfPath !== '' ? $pdfPath : null,
|
||||
'thumbnail_path' => $thumbnailPath !== '' ? $thumbnailPath : null,
|
||||
]);
|
||||
$this->applyRowMeta('territori', $territorio->id, $territorioNode, true);
|
||||
|
||||
$territoriNumeroVisti[$numero] = true;
|
||||
$stats['territori_importati']++;
|
||||
@@ -350,7 +435,24 @@ class XmlExchange extends Component
|
||||
|
||||
$legacyCampagna = (string) ($assegnazioneNode->legacy_campagna_id ?? '');
|
||||
|
||||
Assegnazione::create([
|
||||
// Remap the audit FKs onto the imported users; fall back to the
|
||||
// acting user when the referenced account isn't in the file.
|
||||
$legacyCreatedBy = (string) ($assegnazioneNode->legacy_created_by_id ?? '');
|
||||
$createdBy = ($legacyCreatedBy !== '' && isset($userMap[$legacyCreatedBy]))
|
||||
? $userMap[$legacyCreatedBy]
|
||||
: $actorId;
|
||||
|
||||
$returnedBy = null;
|
||||
if ($returnedAt !== null) {
|
||||
$legacyReturnedBy = (string) ($assegnazioneNode->legacy_returned_by_id ?? '');
|
||||
$returnedBy = ($legacyReturnedBy !== '' && isset($userMap[$legacyReturnedBy]))
|
||||
? $userMap[$legacyReturnedBy]
|
||||
: $actorId;
|
||||
}
|
||||
|
||||
$pdfAccessCode = (string) ($assegnazioneNode->pdf_access_code ?? '');
|
||||
|
||||
$assegnazione = Assegnazione::create([
|
||||
'territorio_id' => $territorioMap[$legacyTerritorio],
|
||||
'proclamatore_id' => $proclamatoreMap[$legacyProclamatore],
|
||||
'anno_teocratico_id' => $annoMap[$legacyAnno],
|
||||
@@ -358,10 +460,13 @@ class XmlExchange extends Component
|
||||
'returned_at' => $returnedAt,
|
||||
'counted_in_campaign' => ((int) ($assegnazioneNode->counted_in_campaign ?? 0)) === 1,
|
||||
'campaign_id' => $legacyCampagna !== '' && isset($campagnaMap[$legacyCampagna]) ? $campagnaMap[$legacyCampagna] : null,
|
||||
'link_sent' => ((int) ($assegnazioneNode->link_sent ?? 0)) === 1,
|
||||
'pdf_access_code' => $pdfAccessCode !== '' ? $pdfAccessCode : null,
|
||||
'note' => (string) ($assegnazioneNode->note ?? ''),
|
||||
'created_by' => $actorId,
|
||||
'returned_by' => $returnedAt !== null ? $actorId : null,
|
||||
'created_by' => $createdBy,
|
||||
'returned_by' => $returnedBy,
|
||||
]);
|
||||
$this->applyRowMeta('assegnazioni', $assegnazione->id, $assegnazioneNode);
|
||||
$stats['assegnazioni_importate']++;
|
||||
}
|
||||
});
|
||||
@@ -379,20 +484,39 @@ class XmlExchange extends Component
|
||||
return [
|
||||
'settings' => [
|
||||
'congregazione_nome' => (string) ($settings->congregazione_nome ?? ''),
|
||||
'public_base_url' => (string) ($settings->public_base_url ?? ''),
|
||||
'logo_path' => (string) ($settings->logo_path ?? ''),
|
||||
'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),
|
||||
'pdf_viewer_show_download' => (int) ((bool) ($settings->pdf_viewer_show_download ?? false)),
|
||||
'audit_retention_days' => (int) ($settings->audit_retention_days ?? 730),
|
||||
'setup_completed' => (int) ((bool) ($settings->setup_completed ?? true)),
|
||||
],
|
||||
'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(),
|
||||
// Full user rows, credentials included. getAuthPassword() bypasses
|
||||
// the $hidden guard to read the raw bcrypt hash; roles come from the
|
||||
// Spatie relation. This is sensitive data — see the note in the
|
||||
// export UI / HANDOFF.
|
||||
'users' => User::query()->with('roles')->orderBy('id')->get()->map(fn ($u) => [
|
||||
'legacy_id' => (string) $u->id,
|
||||
'name' => (string) $u->name,
|
||||
'email' => (string) $u->email,
|
||||
'password' => (string) $u->getAuthPassword(),
|
||||
'email_verified_at' => optional($u->email_verified_at)->toIso8601String() ?? '',
|
||||
'remember_token' => (string) ($u->getRememberToken() ?? ''),
|
||||
'roles' => $u->roles->pluck('name')->all(),
|
||||
'created_at' => optional($u->created_at)->toIso8601String() ?? '',
|
||||
'updated_at' => optional($u->updated_at)->toIso8601String() ?? '',
|
||||
])->all(),
|
||||
'zones' => Zona::query()->orderBy('id')->get(['id', 'nome', 'attivo', 'created_at', 'updated_at'])->toArray(),
|
||||
'tipologie' => Tipologia::query()->orderBy('id')->get(['id', 'nome', 'attivo', 'created_at', 'updated_at'])->toArray(),
|
||||
'proclamatori' => Proclamatore::query()->withTrashed()->orderBy('id')->get(['id', 'nome', 'cognome', 'attivo', 'deleted_at', 'created_at', 'updated_at'])->toArray(),
|
||||
'territori' => Territorio::query()->withTrashed()->orderBy('id')->get(['id', 'numero', 'zona_id', 'tipologia_id', 'confini', 'note', 'attivo', 'prioritario', 'pdf_path', 'thumbnail_path', 'deleted_at', 'created_at', 'updated_at'])->toArray(),
|
||||
'anni_teocratici' => AnnoTeocratico::query()->orderBy('id')->get(['id', 'label', 'start_date', 'end_date', 'created_at', 'updated_at'])->toArray(),
|
||||
'campagne' => Campagna::query()->orderBy('id')->get(['id', 'descrizione', 'start_date', 'end_date', 'created_at', 'updated_at'])->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', 'created_by', 'returned_by', 'link_sent', 'pdf_access_code', 'created_at', 'updated_at'])->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -717,43 +841,59 @@ class XmlExchange extends Component
|
||||
$this->addXmlText($settings, $key, (string) $value);
|
||||
}
|
||||
|
||||
// Users are absent from the legacy-SQL dataset, so guard with ?? [].
|
||||
$usersNode = $xml->addChild('users');
|
||||
foreach (($dataset['users'] ?? []) as $user) {
|
||||
$node = $usersNode->addChild('user');
|
||||
if (isset($user['legacy_id'])) {
|
||||
$node->addAttribute('legacy_id', (string) $user['legacy_id']);
|
||||
}
|
||||
$this->addXmlText($node, 'name', (string) ($user['name'] ?? ''));
|
||||
$this->addXmlText($node, 'email', (string) ($user['email'] ?? ''));
|
||||
$this->addXmlText($node, 'password', (string) ($user['password'] ?? ''));
|
||||
$node->addChild('email_verified_at', (string) ($user['email_verified_at'] ?? ''));
|
||||
$this->addXmlText($node, 'remember_token', (string) ($user['remember_token'] ?? ''));
|
||||
$node->addChild('created_at', (string) ($user['created_at'] ?? ''));
|
||||
$node->addChild('updated_at', (string) ($user['updated_at'] ?? ''));
|
||||
$rolesNode = $node->addChild('roles');
|
||||
foreach (($user['roles'] ?? []) as $roleName) {
|
||||
$this->addXmlText($rolesNode, 'role', (string) $roleName);
|
||||
}
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $zone);
|
||||
$this->addXmlText($node, 'nome', (string) ($zone['nome'] ?? ''));
|
||||
$node->addChild('attivo', (string) ((int) ($zone['attivo'] ?? 1)));
|
||||
$this->addTimestampNodes($node, $zone);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $tipologia);
|
||||
$this->addXmlText($node, 'nome', (string) ($tipologia['nome'] ?? ''));
|
||||
$node->addChild('attivo', (string) ((int) ($tipologia['attivo'] ?? 1)));
|
||||
$this->addTimestampNodes($node, $tipologia);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $proclamatore);
|
||||
$this->addXmlText($node, 'nome', (string) ($proclamatore['nome'] ?? ''));
|
||||
$this->addXmlText($node, 'cognome', (string) ($proclamatore['cognome'] ?? ''));
|
||||
$node->addChild('attivo', (string) ((int) ($proclamatore['attivo'] ?? 1)));
|
||||
$node->addChild('deleted_at', (string) ($proclamatore['deleted_at'] ?? ''));
|
||||
$this->addTimestampNodes($node, $proclamatore);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $territorio);
|
||||
$this->addXmlText($node, 'numero', (string) ($territorio['numero'] ?? ''));
|
||||
$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'] ?? '')));
|
||||
@@ -761,44 +901,49 @@ class XmlExchange extends Component
|
||||
$this->addXmlText($node, 'note', (string) ($territorio['note'] ?? ''));
|
||||
$node->addChild('attivo', (string) ((int) ($territorio['attivo'] ?? 1)));
|
||||
$node->addChild('prioritario', (string) ((int) ($territorio['prioritario'] ?? 0)));
|
||||
$this->addXmlText($node, 'pdf_path', (string) ($territorio['pdf_path'] ?? ''));
|
||||
$this->addXmlText($node, 'thumbnail_path', (string) ($territorio['thumbnail_path'] ?? ''));
|
||||
$node->addChild('deleted_at', (string) ($territorio['deleted_at'] ?? ''));
|
||||
$this->addTimestampNodes($node, $territorio);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $anno);
|
||||
$this->addXmlText($node, 'label', (string) ($anno['label'] ?? ''));
|
||||
$node->addChild('start_date', (string) ($anno['start_date'] ?? ''));
|
||||
$node->addChild('end_date', (string) ($anno['end_date'] ?? ''));
|
||||
$this->addTimestampNodes($node, $anno);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $campagna);
|
||||
$this->addXmlText($node, 'descrizione', (string) ($campagna['descrizione'] ?? ''));
|
||||
$node->addChild('start_date', (string) ($campagna['start_date'] ?? ''));
|
||||
$node->addChild('end_date', (string) ($campagna['end_date'] ?? ''));
|
||||
$this->addTimestampNodes($node, $campagna);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
$this->addLegacyIdAttribute($node, $assegnazione);
|
||||
$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('legacy_created_by_id', (string) ($assegnazione['legacy_created_by_id'] ?? ($assegnazione['created_by'] ?? '')));
|
||||
$node->addChild('legacy_returned_by_id', (string) ($assegnazione['legacy_returned_by_id'] ?? ($assegnazione['returned_by'] ?? '')));
|
||||
$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('link_sent', (string) ((int) ($assegnazione['link_sent'] ?? 0)));
|
||||
$this->addXmlText($node, 'pdf_access_code', (string) ($assegnazione['pdf_access_code'] ?? ''));
|
||||
$this->addXmlText($node, 'note', (string) ($assegnazione['note'] ?? ''));
|
||||
$this->addTimestampNodes($node, $assegnazione);
|
||||
}
|
||||
|
||||
return $xml->asXML() ?: '';
|
||||
@@ -812,4 +957,75 @@ class XmlExchange extends Component
|
||||
|
||||
return $child;
|
||||
}
|
||||
|
||||
private function addTimestampNodes(\SimpleXMLElement $node, array $row): void
|
||||
{
|
||||
$node->addChild('created_at', (string) ($row['created_at'] ?? ''));
|
||||
$node->addChild('updated_at', (string) ($row['updated_at'] ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the legacy_id attribute used to remap foreign keys on import.
|
||||
* The legacy-SQL conversion supplies an explicit 'legacy_id'; the
|
||||
* current-app export supplies the real 'id' — either works as the stable
|
||||
* key the referencing rows (territori, assegnazioni, …) point back to.
|
||||
*/
|
||||
private function addLegacyIdAttribute(\SimpleXMLElement $node, array $row): void
|
||||
{
|
||||
$legacyId = $row['legacy_id'] ?? $row['id'] ?? null;
|
||||
if ($legacyId !== null && (string) $legacyId !== '') {
|
||||
$node->addAttribute('legacy_id', (string) $legacyId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a full datetime (created_at/updated_at/deleted_at/email_verified_at)
|
||||
* for storage, returning a `Y-m-d H:i:s` string or null. Unlike
|
||||
* normalizeDateForDb this keeps the time component.
|
||||
*/
|
||||
private function normalizeDateTimeForDb(string $raw): ?string
|
||||
{
|
||||
$raw = trim($raw);
|
||||
if ($raw === '' || str_starts_with($raw, '0000-00-00')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return Carbon::parse($raw)->toDateTimeString();
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore created_at/updated_at (and deleted_at, when the model soft
|
||||
* deletes) from the XML node after the row has been created. Written with
|
||||
* the query builder so Eloquent does not stamp its own timestamps over the
|
||||
* imported values. Only columns present in the XML are touched.
|
||||
*/
|
||||
private function applyRowMeta(string $table, int $id, \SimpleXMLElement $node, bool $withSoftDelete = false): void
|
||||
{
|
||||
$updates = [];
|
||||
|
||||
$createdAt = $this->normalizeDateTimeForDb((string) ($node->created_at ?? ''));
|
||||
if ($createdAt !== null) {
|
||||
$updates['created_at'] = $createdAt;
|
||||
}
|
||||
|
||||
$updatedAt = $this->normalizeDateTimeForDb((string) ($node->updated_at ?? ''));
|
||||
if ($updatedAt !== null) {
|
||||
$updates['updated_at'] = $updatedAt;
|
||||
}
|
||||
|
||||
if ($withSoftDelete) {
|
||||
$deletedAt = $this->normalizeDateTimeForDb((string) ($node->deleted_at ?? ''));
|
||||
if ($deletedAt !== null) {
|
||||
$updates['deleted_at'] = $deletedAt;
|
||||
}
|
||||
}
|
||||
|
||||
if ($updates !== []) {
|
||||
DB::table($table)->where('id', $id)->update($updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user