239 lines
7.7 KiB
PHP
239 lines
7.7 KiB
PHP
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\RubricaUniversale;
|
|
use App\Models\Titolo;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class GesconBackfillRubricaLegacyIdentityCommand extends Command
|
|
{
|
|
protected $signature = 'gescon:backfill-rubrica-legacy-identity
|
|
{--apply : Applica realmente le modifiche}
|
|
{--limit=5000 : Numero massimo di record da analizzare}
|
|
{--id=* : Limita l\'analisi a specifici ID rubrica}';
|
|
|
|
protected $description = 'Sposta i dati anagrafici legacy dalle note ai campi strutturati della rubrica_universale.';
|
|
|
|
public function handle(): int
|
|
{
|
|
if (! Schema::hasTable('rubrica_universale')) {
|
|
$this->error('Tabella rubrica_universale non disponibile.');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$apply = (bool) $this->option('apply');
|
|
$limit = max(1, min((int) $this->option('limit'), 50000));
|
|
$ids = array_values(array_filter(array_map(fn($value) => is_numeric($value) ? (int) $value : 0, (array) $this->option('id'))));
|
|
|
|
$query = RubricaUniversale::query()
|
|
->where('note', 'like', '%Dati anagrafici legacy:%')
|
|
->orderBy('id')
|
|
->limit($limit);
|
|
|
|
if ($ids !== []) {
|
|
$query->whereIn('id', $ids);
|
|
}
|
|
|
|
$rows = $query->get();
|
|
if ($rows->isEmpty()) {
|
|
$this->info('Nessun record da bonificare.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$processed = 0;
|
|
$updated = 0;
|
|
|
|
foreach ($rows as $rubrica) {
|
|
$processed++;
|
|
$legacy = $this->extractLegacyIdentityFromNote($rubrica->note);
|
|
$changes = [];
|
|
|
|
if (! $rubrica->titolo_id && ! empty($legacy['titolo_id'])) {
|
|
$changes['titolo_id'] = (int) $legacy['titolo_id'];
|
|
}
|
|
if (! $rubrica->sesso && ! empty($legacy['sesso'])) {
|
|
$changes['sesso'] = $legacy['sesso'];
|
|
}
|
|
if ((! $rubrica->data_nascita || (int) optional($rubrica->data_nascita)->format('Y') > (int) now()->format('Y') + 1) && ! empty($legacy['data_nascita'])) {
|
|
$changes['data_nascita'] = $legacy['data_nascita'];
|
|
}
|
|
if (! $rubrica->luogo_nascita && ! empty($legacy['luogo_nascita'])) {
|
|
$changes['luogo_nascita'] = $legacy['luogo_nascita'];
|
|
}
|
|
if (! $rubrica->provincia_nascita && ! empty($legacy['provincia_nascita'])) {
|
|
$changes['provincia_nascita'] = $legacy['provincia_nascita'];
|
|
}
|
|
|
|
$cleanNote = $legacy['note_clean'] ?? null;
|
|
if (($rubrica->note ?? null) !== $cleanNote) {
|
|
$changes['note'] = $cleanNote;
|
|
}
|
|
|
|
if ($changes === []) {
|
|
continue;
|
|
}
|
|
|
|
$updated++;
|
|
|
|
if ($apply) {
|
|
$rubrica->fill($changes);
|
|
$rubrica->save();
|
|
}
|
|
}
|
|
|
|
$this->info(($apply ? 'Bonifica eseguita' : 'Dry-run bonifica') . ": processati {$processed}, aggiornabili {$updated}");
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
private function extractLegacyIdentityFromNote(mixed $note): array
|
|
{
|
|
$raw = trim((string) ($note ?? ''));
|
|
if ($raw === '') {
|
|
return [
|
|
'note_clean' => null,
|
|
'titolo_id' => null,
|
|
'sesso' => null,
|
|
'data_nascita' => null,
|
|
'luogo_nascita' => null,
|
|
'provincia_nascita' => null,
|
|
];
|
|
}
|
|
|
|
$parsed = [
|
|
'titolo_id' => null,
|
|
'sesso' => null,
|
|
'data_nascita' => null,
|
|
'luogo_nascita' => null,
|
|
'provincia_nascita' => null,
|
|
];
|
|
|
|
$cleanLines = [];
|
|
foreach (preg_split('/\r\n|\r|\n/', $raw) ?: [] as $line) {
|
|
$trimmed = trim($line);
|
|
if (! str_starts_with($trimmed, 'Dati anagrafici legacy:')) {
|
|
if ($trimmed !== '') {
|
|
$cleanLines[] = $line;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$payload = trim(substr($trimmed, strlen('Dati anagrafici legacy:')));
|
|
$bits = preg_split('/\s*\|\s*/', $payload) ?: [];
|
|
foreach ($bits as $bit) {
|
|
[$key, $value] = array_pad(explode(':', $bit, 2), 2, null);
|
|
$key = mb_strtolower(trim((string) $key));
|
|
$value = trim((string) $value);
|
|
if ($value === '') {
|
|
continue;
|
|
}
|
|
|
|
if ($key === 'titolo') {
|
|
$parsed['titolo_id'] = $this->resolveTitoloId($value);
|
|
continue;
|
|
}
|
|
if ($key === 'sesso') {
|
|
$parsed['sesso'] = $this->normalizeSessoValue($value);
|
|
continue;
|
|
}
|
|
if ($key === 'data nascita') {
|
|
$parsed['data_nascita'] = $this->normalizeLegacyDateValue($value);
|
|
continue;
|
|
}
|
|
if ($key === 'luogo nascita') {
|
|
$parsed['luogo_nascita'] = $value;
|
|
continue;
|
|
}
|
|
if ($key === 'provincia nascita') {
|
|
$parsed['provincia_nascita'] = $this->normalizeProvince($value);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $parsed + [
|
|
'note_clean' => $cleanLines === [] ? null : implode("\n", $cleanLines),
|
|
];
|
|
}
|
|
|
|
private function normalizeLegacyDateValue(mixed $value): ?string
|
|
{
|
|
$raw = trim((string) ($value ?? ''));
|
|
if ($raw === '') {
|
|
return null;
|
|
}
|
|
|
|
foreach (['Y-m-d', 'd/m/Y', 'd-m-Y', 'm/d/Y', 'd.m.Y', 'd/m/y', 'd-m-y', 'm/d/y', 'd.m.y'] as $format) {
|
|
$dt = \DateTime::createFromFormat($format, $raw);
|
|
if ($dt instanceof \DateTime) {
|
|
return $this->normalizeBirthDateYear($dt);
|
|
}
|
|
}
|
|
|
|
$timestamp = strtotime($raw);
|
|
if ($timestamp === false) {
|
|
return null;
|
|
}
|
|
|
|
return $this->normalizeBirthDateYear((new \DateTime())->setTimestamp($timestamp));
|
|
}
|
|
|
|
private function normalizeBirthDateYear(\DateTime $date): ?string
|
|
{
|
|
$year = (int) $date->format('Y');
|
|
$currentYear = (int) now()->format('Y');
|
|
|
|
if ($year > $currentYear + 1) {
|
|
$date->modify('-100 years');
|
|
$year = (int) $date->format('Y');
|
|
}
|
|
|
|
if ($year < 1900 || $year > $currentYear + 1) {
|
|
return null;
|
|
}
|
|
|
|
return $date->format('Y-m-d');
|
|
}
|
|
|
|
private function normalizeSessoValue(mixed $value): ?string
|
|
{
|
|
$raw = strtoupper(trim((string) ($value ?? '')));
|
|
|
|
return match (true) {
|
|
$raw === 'M', str_starts_with($raw, 'MAS') => 'M',
|
|
$raw === 'F', str_starts_with($raw, 'FEM') => 'F',
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
private function normalizeProvince(mixed $value): ?string
|
|
{
|
|
$raw = strtoupper(trim((string) ($value ?? '')));
|
|
if ($raw === '') {
|
|
return null;
|
|
}
|
|
|
|
return mb_substr($raw, 0, 2);
|
|
}
|
|
|
|
private function resolveTitoloId(string $value): ?int
|
|
{
|
|
if (! Schema::hasTable('titoli')) {
|
|
return null;
|
|
}
|
|
|
|
$key = mb_strtolower(trim($value));
|
|
if ($key === '') {
|
|
return null;
|
|
}
|
|
|
|
$titolo = Titolo::query()
|
|
->whereRaw('LOWER(sigla) = ?', [$key])
|
|
->orWhereRaw('LOWER(nome) = ?', [$key])
|
|
->first();
|
|
|
|
return $titolo?->id ? (int) $titolo->id : null;
|
|
}
|
|
}
|