993 lines
38 KiB
PHP
993 lines
38 KiB
PHP
<?php
|
||
namespace App\Services;
|
||
|
||
use App\Models\Amministratore;
|
||
use App\Models\Stabile;
|
||
use Exception;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\File;
|
||
use ZipArchive;
|
||
|
||
class MigrationService
|
||
{
|
||
protected DatabaseManagerService $dbManager;
|
||
protected TenantArchivePathService $tenantArchivePath;
|
||
|
||
public function __construct(DatabaseManagerService $dbManager, TenantArchivePathService $tenantArchivePath)
|
||
{
|
||
$this->dbManager = $dbManager;
|
||
$this->tenantArchivePath = $tenantArchivePath;
|
||
}
|
||
|
||
/**
|
||
* Prepara migrazione completa amministratore
|
||
*/
|
||
public function prepareAmministratoreMigration(Amministratore $amministratore): array
|
||
{
|
||
try {
|
||
$migrationId = "migration_admin_{$amministratore->codice_univoco}_" . date('Y-m-d_H-i-s');
|
||
$migrationPath = storage_path("app/migrations/{$migrationId}");
|
||
|
||
if (! is_dir($migrationPath)) {
|
||
mkdir($migrationPath, 0755, true);
|
||
}
|
||
|
||
$results = [
|
||
'migration_id' => $migrationId,
|
||
'amministratore' => $amministratore->codice_univoco,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'components' => [],
|
||
];
|
||
|
||
// 1. Backup database amministratore
|
||
$adminDbBackup = $this->dbManager->backupAmministratoreDatabase($amministratore);
|
||
if (! $adminDbBackup['success']) {
|
||
throw new Exception('Errore backup database amministratore: ' . $adminDbBackup['error']);
|
||
}
|
||
$results['components']['admin_database'] = $adminDbBackup;
|
||
|
||
// 2. Backup database per ogni stabile
|
||
$stabiliBackups = [];
|
||
foreach ($amministratore->stabili as $stabile) {
|
||
if ($stabile->database_dedicato) {
|
||
$stabileBackup = $this->dbManager->backupStabileDatabase($stabile);
|
||
if ($stabileBackup['success']) {
|
||
$stabiliBackups[$stabile->codice_stabile] = $stabileBackup;
|
||
}
|
||
}
|
||
}
|
||
$results['components']['stabili_databases'] = $stabiliBackups;
|
||
|
||
// 3. Archivio file sistema
|
||
$archiveResult = $this->createFileSystemArchive($amministratore, $migrationPath);
|
||
$results['components']['filesystem_archive'] = $archiveResult;
|
||
|
||
// 4. Metadata e configurazioni
|
||
$metadataResult = $this->createMigrationMetadata($amministratore, $migrationPath);
|
||
$results['components']['metadata'] = $metadataResult;
|
||
|
||
// 5. Script di ricostruzione
|
||
$scriptsResult = $this->createMigrationScripts($amministratore, $migrationPath);
|
||
$results['components']['scripts'] = $scriptsResult;
|
||
|
||
// 6. Verifica integrità
|
||
$verificationResult = $this->verifyMigrationIntegrity($migrationPath);
|
||
$results['components']['verification'] = $verificationResult;
|
||
|
||
// 7. Crea package finale
|
||
$packageResult = $this->createMigrationPackage($migrationId, $migrationPath);
|
||
$results['package'] = $packageResult;
|
||
|
||
return [
|
||
'success' => true,
|
||
'migration' => $results,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Prepara migrazione singolo stabile
|
||
*/
|
||
public function prepareStabileMigration(Stabile $stabile): array
|
||
{
|
||
try {
|
||
$migrationId = "migration_stabile_{$stabile->codice_stabile}_" . date('Y-m-d_H-i-s');
|
||
$migrationPath = storage_path("app/migrations/{$migrationId}");
|
||
|
||
if (! is_dir($migrationPath)) {
|
||
mkdir($migrationPath, 0755, true);
|
||
}
|
||
|
||
$results = [
|
||
'migration_id' => $migrationId,
|
||
'stabile' => $stabile->codice_stabile,
|
||
'amministratore' => $stabile->amministratore->codice_univoco,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'components' => [],
|
||
];
|
||
|
||
// 1. Backup database stabile
|
||
if ($stabile->database_dedicato) {
|
||
$stabileDbBackup = $this->dbManager->backupStabileDatabase($stabile);
|
||
if (! $stabileDbBackup['success']) {
|
||
throw new Exception('Errore backup database stabile: ' . $stabileDbBackup['error']);
|
||
}
|
||
$results['components']['stabile_database'] = $stabileDbBackup;
|
||
}
|
||
|
||
// 2. Archivio file stabile
|
||
$archiveResult = $this->createStabileFileArchive($stabile, $migrationPath);
|
||
$results['components']['filesystem_archive'] = $archiveResult;
|
||
|
||
// 3. Metadata stabile
|
||
$metadataResult = $this->createStabileMetadata($stabile, $migrationPath);
|
||
$results['components']['metadata'] = $metadataResult;
|
||
|
||
// 4. Package finale
|
||
$packageResult = $this->createMigrationPackage($migrationId, $migrationPath);
|
||
$results['package'] = $packageResult;
|
||
|
||
return [
|
||
'success' => true,
|
||
'migration' => $results,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea archivio completo file system amministratore
|
||
*/
|
||
private function createFileSystemArchive(Amministratore $amministratore, string $migrationPath): array
|
||
{
|
||
try {
|
||
$sourcePath = $this->tenantArchivePath->amministratoreAbsolutePath($amministratore);
|
||
$archiveName = "filesystem_admin_{$amministratore->codice_univoco}.zip";
|
||
$archivePath = $migrationPath . '/' . $archiveName;
|
||
|
||
if (! is_dir($sourcePath)) {
|
||
throw new Exception("Cartella amministratore non trovata: {$sourcePath}");
|
||
}
|
||
|
||
$zip = new ZipArchive();
|
||
if ($zip->open($archivePath, ZipArchive::CREATE) !== true) {
|
||
throw new Exception('Impossibile creare archivio filesystem');
|
||
}
|
||
|
||
$iterator = new \RecursiveIteratorIterator(
|
||
new \RecursiveDirectoryIterator($sourcePath, \RecursiveDirectoryIterator::SKIP_DOTS)
|
||
);
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isFile()) {
|
||
$relativePath = str_replace($sourcePath . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
||
$zip->addFile($file->getPathname(), $relativePath);
|
||
}
|
||
}
|
||
|
||
$zip->close();
|
||
|
||
return [
|
||
'success' => true,
|
||
'archive_name' => $archiveName,
|
||
'archive_path' => $archivePath,
|
||
'archive_size' => filesize($archivePath),
|
||
'files_count' => $zip->numFiles ?? 0,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea archivio file singolo stabile
|
||
*/
|
||
private function createStabileFileArchive(Stabile $stabile, string $migrationPath): array
|
||
{
|
||
try {
|
||
$sourcePath = $this->tenantArchivePath->stabileAbsolutePath($stabile);
|
||
$archiveName = "filesystem_stabile_{$stabile->codice_stabile}.zip";
|
||
$archivePath = $migrationPath . '/' . $archiveName;
|
||
|
||
if (! is_dir($sourcePath)) {
|
||
// Crea struttura base se non esiste
|
||
$this->createStabileFolderStructure($stabile);
|
||
}
|
||
|
||
$zip = new ZipArchive();
|
||
if ($zip->open($archivePath, ZipArchive::CREATE) !== true) {
|
||
throw new Exception('Impossibile creare archivio filesystem stabile');
|
||
}
|
||
|
||
$iterator = new \RecursiveIteratorIterator(
|
||
new \RecursiveDirectoryIterator($sourcePath, \RecursiveDirectoryIterator::SKIP_DOTS)
|
||
);
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isFile()) {
|
||
$relativePath = str_replace($sourcePath . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
||
$zip->addFile($file->getPathname(), $relativePath);
|
||
}
|
||
}
|
||
|
||
$zip->close();
|
||
|
||
return [
|
||
'success' => true,
|
||
'archive_name' => $archiveName,
|
||
'archive_path' => $archivePath,
|
||
'archive_size' => filesize($archivePath),
|
||
'files_count' => $zip->numFiles ?? 0,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea metadata completi per migrazione
|
||
*/
|
||
private function createMigrationMetadata(Amministratore $amministratore, string $migrationPath): array
|
||
{
|
||
try {
|
||
$metadata = [
|
||
'migration' => [
|
||
'type' => 'amministratore_completo',
|
||
'version' => '1.0.0',
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'source_server' => env('APP_URL'),
|
||
'netgescon_version' => '2.1.0',
|
||
],
|
||
'amministratore' => [
|
||
'id' => $amministratore->id,
|
||
'codice_univoco' => $amministratore->codice_univoco,
|
||
'nome' => $amministratore->nome,
|
||
'cognome' => $amministratore->cognome,
|
||
'denominazione_studio' => $amministratore->denominazione_studio,
|
||
'partita_iva' => $amministratore->partita_iva,
|
||
'codice_fiscale_studio' => $amministratore->codice_fiscale_studio,
|
||
'email_studio' => $amministratore->email_studio,
|
||
'database_principale' => $amministratore->getDatabaseName(),
|
||
'created_at' => $amministratore->created_at->toISOString(),
|
||
],
|
||
'stabili' => [],
|
||
'databases' => [
|
||
'principale' => $amministratore->getDatabaseName(),
|
||
'stabili' => [],
|
||
],
|
||
'requirements' => [
|
||
'php_version' => PHP_VERSION,
|
||
'laravel_version' => app()->version(),
|
||
'mysql_version' => DB::select('SELECT VERSION() as version')[0]->version,
|
||
'required_extensions' => [
|
||
'zip',
|
||
'pdo_mysql',
|
||
'openssl',
|
||
'fileinfo',
|
||
'mbstring',
|
||
],
|
||
'min_disk_space_mb' => $this->calculateRequiredSpace($amministratore),
|
||
],
|
||
'structure' => [
|
||
'folders' => $this->analyzeFolderStructure($amministratore),
|
||
'databases' => $this->analyzeDatabaseStructure($amministratore),
|
||
],
|
||
];
|
||
|
||
// Aggiungi info per ogni stabile
|
||
foreach ($amministratore->stabili as $stabile) {
|
||
$stabileInfo = [
|
||
'id' => $stabile->id,
|
||
'codice_stabile' => $stabile->codice_stabile,
|
||
'denominazione' => $stabile->denominazione,
|
||
'indirizzo' => $stabile->indirizzo . ', ' . $stabile->citta,
|
||
'database_dedicato' => $stabile->database_dedicato,
|
||
'created_at' => $stabile->created_at->toISOString(),
|
||
];
|
||
|
||
$metadata['stabili'][] = $stabileInfo;
|
||
|
||
if ($stabile->database_dedicato) {
|
||
$metadata['databases']['stabili'][] = $stabile->database_dedicato;
|
||
}
|
||
}
|
||
|
||
$metadataPath = $migrationPath . '/metadata.json';
|
||
file_put_contents($metadataPath, json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||
|
||
return [
|
||
'success' => true,
|
||
'metadata_file' => $metadataPath,
|
||
'stabili_count' => count($metadata['stabili']),
|
||
'databases_count' => count($metadata['databases']['stabili']) + 1,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea metadata per singolo stabile
|
||
*/
|
||
private function createStabileMetadata(Stabile $stabile, string $migrationPath): array
|
||
{
|
||
try {
|
||
$metadata = [
|
||
'migration' => [
|
||
'type' => 'stabile_singolo',
|
||
'version' => '1.0.0',
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'source_server' => env('APP_URL'),
|
||
],
|
||
'stabile' => [
|
||
'id' => $stabile->id,
|
||
'codice_stabile' => $stabile->codice_stabile,
|
||
'denominazione' => $stabile->denominazione,
|
||
'indirizzo' => $stabile->indirizzo,
|
||
'cap' => $stabile->cap,
|
||
'citta' => $stabile->citta,
|
||
'provincia' => $stabile->provincia,
|
||
'database_dedicato' => $stabile->database_dedicato,
|
||
'created_at' => $stabile->created_at->toISOString(),
|
||
],
|
||
'amministratore_origine' => [
|
||
'codice_univoco' => $stabile->amministratore->codice_univoco,
|
||
'nome_completo' => $stabile->amministratore->nome_completo,
|
||
'denominazione_studio' => $stabile->amministratore->denominazione_studio,
|
||
],
|
||
'requirements' => [
|
||
'target_admin_code' => 'required',
|
||
'php_version' => PHP_VERSION,
|
||
'mysql_version' => DB::select('SELECT VERSION() as version')[0]->version,
|
||
],
|
||
];
|
||
|
||
$metadataPath = $migrationPath . '/stabile_metadata.json';
|
||
file_put_contents($metadataPath, json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||
|
||
return [
|
||
'success' => true,
|
||
'metadata_file' => $metadataPath,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea script di ricostruzione ambiente
|
||
*/
|
||
private function createMigrationScripts(Amministratore $amministratore, string $migrationPath): array
|
||
{
|
||
try {
|
||
$scriptsPath = $migrationPath . '/scripts';
|
||
if (! is_dir($scriptsPath)) {
|
||
mkdir($scriptsPath, 0755, true);
|
||
}
|
||
|
||
// 1. Script restore database
|
||
$restoreDbScript = $this->createDatabaseRestoreScript($amministratore);
|
||
file_put_contents($scriptsPath . '/restore_databases.sh', $restoreDbScript);
|
||
|
||
// 2. Script restore filesystem
|
||
$restoreFsScript = $this->createFilesystemRestoreScript($amministratore);
|
||
file_put_contents($scriptsPath . '/restore_filesystem.sh', $restoreFsScript);
|
||
|
||
// 3. Script verifica post-migrazione
|
||
$verifyScript = $this->createVerificationScript($amministratore);
|
||
file_put_contents($scriptsPath . '/verify_migration.sh', $verifyScript);
|
||
|
||
// 4. Script PHP per ricostruzione record
|
||
$phpScript = $this->createPhpRestoreScript($amministratore);
|
||
file_put_contents($scriptsPath . '/restore_records.php', $phpScript);
|
||
|
||
// 5. README istruzioni
|
||
$readme = $this->createMigrationReadme($amministratore);
|
||
file_put_contents($scriptsPath . '/README.md', $readme);
|
||
|
||
// Rendi script eseguibili
|
||
chmod($scriptsPath . '/restore_databases.sh', 0755);
|
||
chmod($scriptsPath . '/restore_filesystem.sh', 0755);
|
||
chmod($scriptsPath . '/verify_migration.sh', 0755);
|
||
|
||
return [
|
||
'success' => true,
|
||
'scripts_path' => $scriptsPath,
|
||
'scripts_created' => 5,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea script restore database
|
||
*/
|
||
private function createDatabaseRestoreScript(Amministratore $amministratore): string
|
||
{
|
||
$script = "#!/bin/bash\n\n";
|
||
$script .= "# Script restore database per amministratore {$amministratore->codice_univoco}\n";
|
||
$script .= "# Generato automaticamente da NetGescon\n\n";
|
||
|
||
$script .= "set -e\n\n";
|
||
|
||
$script .= "# Configurazione\n";
|
||
$script .= "ADMIN_CODE=\"{$amministratore->codice_univoco}\"\n";
|
||
$script .= "ADMIN_DB=\"netgescon_admin_{$amministratore->codice_univoco}\"\n";
|
||
$script .= "MYSQL_USER=\"\${MYSQL_USER:-root}\"\n";
|
||
$script .= "MYSQL_PASS=\"\${MYSQL_PASS}\"\n";
|
||
$script .= "MYSQL_HOST=\"\${MYSQL_HOST:-localhost}\"\n\n";
|
||
|
||
$script .= "echo \"🚀 Inizio restore database amministratore \$ADMIN_CODE\"\n\n";
|
||
|
||
$script .= "# Crea database amministratore\n";
|
||
$script .= "echo \"📦 Creazione database \$ADMIN_DB\"\n";
|
||
$script .= "mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS -e \"CREATE DATABASE IF NOT EXISTS \\\`\$ADMIN_DB\\\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci\"\n\n";
|
||
|
||
$script .= "# Restore database amministratore\n";
|
||
$script .= "if [ -f \"../database_backups/backup_admin_\${ADMIN_CODE}_*.sql\" ]; then\n";
|
||
$script .= " ADMIN_BACKUP=\$(ls ../database_backups/backup_admin_\${ADMIN_CODE}_*.sql | head -1)\n";
|
||
$script .= " echo \"📥 Restore database amministratore da \$ADMIN_BACKUP\"\n";
|
||
$script .= " mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS \$ADMIN_DB < \$ADMIN_BACKUP\n";
|
||
$script .= " echo \"✅ Database amministratore ripristinato\"\n";
|
||
$script .= "else\n";
|
||
$script .= " echo \"❌ Backup database amministratore non trovato\"\n";
|
||
$script .= " exit 1\n";
|
||
$script .= "fi\n\n";
|
||
|
||
// Aggiungi restore per ogni stabile
|
||
foreach ($amministratore->stabili as $stabile) {
|
||
if ($stabile->database_dedicato) {
|
||
$script .= "# Restore database stabile {$stabile->codice_stabile}\n";
|
||
$script .= "STABILE_DB=\"{$stabile->database_dedicato}\"\n";
|
||
$script .= "echo \"📦 Creazione database stabile \$STABILE_DB\"\n";
|
||
$script .= "mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS -e \"CREATE DATABASE IF NOT EXISTS \\\`\$STABILE_DB\\\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci\"\n";
|
||
$script .= "if [ -f \"../database_backups/backup_stabile_{$stabile->codice_stabile}_*.sql\" ]; then\n";
|
||
$script .= " STABILE_BACKUP=\$(ls ../database_backups/backup_stabile_{$stabile->codice_stabile}_*.sql | head -1)\n";
|
||
$script .= " echo \"📥 Restore database stabile da \$STABILE_BACKUP\"\n";
|
||
$script .= " mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS \$STABILE_DB < \$STABILE_BACKUP\n";
|
||
$script .= " echo \"✅ Database stabile {$stabile->codice_stabile} ripristinato\"\n";
|
||
$script .= "else\n";
|
||
$script .= " echo \"⚠️ Backup database stabile {$stabile->codice_stabile} non trovato\"\n";
|
||
$script .= "fi\n\n";
|
||
}
|
||
}
|
||
|
||
$script .= "echo \"🎉 Restore database completato!\"\n";
|
||
|
||
return $script;
|
||
}
|
||
|
||
/**
|
||
* Crea script restore filesystem
|
||
*/
|
||
private function createFilesystemRestoreScript(Amministratore $amministratore): string
|
||
{
|
||
$script = "#!/bin/bash\n\n";
|
||
$script .= "# Script restore filesystem per amministratore {$amministratore->codice_univoco}\n\n";
|
||
|
||
$script .= "set -e\n\n";
|
||
|
||
$script .= "ADMIN_CODE=\"{$amministratore->codice_univoco}\"\n";
|
||
$script .= "TARGET_PATH=\"\${TARGET_PATH:-/var/www/netgescon/storage/app/amministratori}\"\n\n";
|
||
|
||
$script .= "echo \"🚀 Inizio restore filesystem amministratore \$ADMIN_CODE\"\n\n";
|
||
|
||
$script .= "# Crea directory target\n";
|
||
$script .= "mkdir -p \"\$TARGET_PATH/\$ADMIN_CODE\"\n\n";
|
||
|
||
$script .= "# Estrai archivio filesystem\n";
|
||
$script .= "if [ -f \"../filesystem_admin_\${ADMIN_CODE}.zip\" ]; then\n";
|
||
$script .= " echo \"📥 Estrazione archivio filesystem\"\n";
|
||
$script .= " cd \"\$TARGET_PATH/\$ADMIN_CODE\"\n";
|
||
$script .= " unzip -q \"../../../migrations/\$(basename \$PWD)/filesystem_admin_\${ADMIN_CODE}.zip\"\n";
|
||
$script .= " echo \"✅ Filesystem ripristinato in \$TARGET_PATH/\$ADMIN_CODE\"\n";
|
||
$script .= "else\n";
|
||
$script .= " echo \"❌ Archivio filesystem non trovato\"\n";
|
||
$script .= " exit 1\n";
|
||
$script .= "fi\n\n";
|
||
|
||
$script .= "# Imposta permessi\n";
|
||
$script .= "echo \"🔧 Impostazione permessi\"\n";
|
||
$script .= "chown -R www-data:www-data \"\$TARGET_PATH/\$ADMIN_CODE\"\n";
|
||
$script .= "find \"\$TARGET_PATH/\$ADMIN_CODE\" -type d -exec chmod 755 {} \\;\n";
|
||
$script .= "find \"\$TARGET_PATH/\$ADMIN_CODE\" -type f -exec chmod 644 {} \\;\n\n";
|
||
|
||
$script .= "echo \"🎉 Restore filesystem completato!\"\n";
|
||
|
||
return $script;
|
||
}
|
||
|
||
/**
|
||
* Crea script verifica post-migrazione
|
||
*/
|
||
private function createVerificationScript(Amministratore $amministratore): string
|
||
{
|
||
$script = "#!/bin/bash\n\n";
|
||
$script .= "# Script verifica migrazione per amministratore {$amministratore->codice_univoco}\n\n";
|
||
|
||
$script .= "ADMIN_CODE=\"{$amministratore->codice_univoco}\"\n";
|
||
$script .= "ADMIN_DB=\"netgescon_admin_{$amministratore->codice_univoco}\"\n";
|
||
$script .= "MYSQL_USER=\"\${MYSQL_USER:-root}\"\n";
|
||
$script .= "MYSQL_PASS=\"\${MYSQL_PASS}\"\n";
|
||
$script .= "MYSQL_HOST=\"\${MYSQL_HOST:-localhost}\"\n\n";
|
||
|
||
$script .= "echo \"🔍 Verifica migrazione amministratore \$ADMIN_CODE\"\n\n";
|
||
|
||
$script .= "# Verifica database\n";
|
||
$script .= "echo \"📊 Verifica database...\"\n";
|
||
$script .= "DB_EXISTS=\$(mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS -e \"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='\$ADMIN_DB'\" | grep -v SCHEMA_NAME | wc -l)\n";
|
||
$script .= "if [ \$DB_EXISTS -eq 1 ]; then\n";
|
||
$script .= " echo \"✅ Database amministratore presente\"\n";
|
||
$script .= " TABLE_COUNT=\$(mysql -h\$MYSQL_HOST -u\$MYSQL_USER -p\$MYSQL_PASS -e \"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='\$ADMIN_DB'\" | tail -1)\n";
|
||
$script .= " echo \"📋 Tabelle trovate: \$TABLE_COUNT\"\n";
|
||
$script .= "else\n";
|
||
$script .= " echo \"❌ Database amministratore mancante\"\n";
|
||
$script .= "fi\n\n";
|
||
|
||
$script .= "# Verifica filesystem\n";
|
||
$script .= "echo \"📁 Verifica filesystem...\"\n";
|
||
$script .= "ADMIN_PATH=\"/var/www/netgescon/storage/app/amministratori/\$ADMIN_CODE\"\n";
|
||
$script .= "if [ -d \"\$ADMIN_PATH\" ]; then\n";
|
||
$script .= " echo \"✅ Cartella amministratore presente\"\n";
|
||
$script .= " FILE_COUNT=\$(find \"\$ADMIN_PATH\" -type f | wc -l)\n";
|
||
$script .= " echo \"📄 File trovati: \$FILE_COUNT\"\n";
|
||
$script .= "else\n";
|
||
$script .= " echo \"❌ Cartella amministratore mancante\"\n";
|
||
$script .= "fi\n\n";
|
||
|
||
$script .= "echo \"🎯 Verifica completata!\"\n";
|
||
|
||
return $script;
|
||
}
|
||
|
||
/**
|
||
* Crea script PHP per restore record
|
||
*/
|
||
private function createPhpRestoreScript(Amministratore $amministratore): string
|
||
{
|
||
return "<?php
|
||
|
||
/*
|
||
* Script PHP per restore record amministratore {$amministratore->codice_univoco}
|
||
* Da eseguire dopo restore database e filesystem
|
||
*/
|
||
|
||
require_once __DIR__ . '/../../../../vendor/autoload.php';
|
||
|
||
use Illuminate\\Support\\Facades\\DB;
|
||
use App\\Models\\Amministratore;
|
||
use App\\Models\\User;
|
||
|
||
// Carica configurazione Laravel
|
||
\$app = require_once __DIR__ . '/../../../../bootstrap/app.php';
|
||
\$app->make(Illuminate\\Contracts\\Console\\Kernel::class)->bootstrap();
|
||
|
||
try {
|
||
echo \"🚀 Inizio restore record amministratore {$amministratore->codice_univoco}\\n\";
|
||
|
||
// Leggi metadata
|
||
\$metadata = json_decode(file_get_contents(__DIR__ . '/../metadata.json'), true);
|
||
\$adminData = \$metadata['amministratore'];
|
||
|
||
// Verifica se amministratore esiste già
|
||
\$esistente = Amministratore::where('codice_univoco', '{$amministratore->codice_univoco}')->first();
|
||
|
||
if (\$esistente) {
|
||
echo \"⚠️ Amministratore {$amministratore->codice_univoco} già presente, aggiorno record...\\n\";
|
||
|
||
\$esistente->update([
|
||
'database_attivo' => \$adminData['database_principale']
|
||
]);
|
||
|
||
\$amministratore = \$esistente;
|
||
} else {
|
||
echo \"➕ Creazione nuovo record amministratore...\\n\";
|
||
|
||
// Crea/trova utente
|
||
\$user = User::where('email', \$adminData['email_studio'])->first();
|
||
if (!\$user) {
|
||
\$user = User::create([
|
||
'name' => \$adminData['nome'] . ' ' . \$adminData['cognome'],
|
||
'email' => \$adminData['email_studio'],
|
||
'password' => bcrypt('temp_password_' . uniqid()),
|
||
'email_verified_at' => now(),
|
||
]);
|
||
}
|
||
|
||
// Crea amministratore
|
||
\$amministratore = Amministratore::create([
|
||
'user_id' => \$user->id,
|
||
'nome' => \$adminData['nome'],
|
||
'cognome' => \$adminData['cognome'],
|
||
'denominazione_studio' => \$adminData['denominazione_studio'],
|
||
'partita_iva' => \$adminData['partita_iva'],
|
||
'codice_fiscale_studio' => \$adminData['codice_fiscale_studio'],
|
||
'email_studio' => \$adminData['email_studio'],
|
||
'codice_univoco' => '{$amministratore->codice_univoco}',
|
||
'database_attivo' => \$adminData['database_principale']
|
||
]);
|
||
}
|
||
|
||
echo \"✅ Record amministratore ripristinato (ID: {\$amministratore->id})\\n\";
|
||
|
||
// Restore stabili
|
||
foreach (\$metadata['stabili'] as \$stabileData) {
|
||
\$stabile = \$amministratore->stabili()->where('codice_stabile', \$stabileData['codice_stabile'])->first();
|
||
|
||
if (!\$stabile) {
|
||
\$stabile = \$amministratore->stabili()->create([
|
||
'codice_stabile' => \$stabileData['codice_stabile'],
|
||
'denominazione' => \$stabileData['denominazione'],
|
||
'indirizzo' => 'Da aggiornare',
|
||
'cap' => '00000',
|
||
'citta' => 'Da aggiornare',
|
||
'provincia' => 'XX',
|
||
'database_dedicato' => \$stabileData['database_dedicato']
|
||
]);
|
||
|
||
echo \"➕ Stabile {\$stabileData['codice_stabile']} creato\\n\";
|
||
} else {
|
||
\$stabile->update(['database_dedicato' => \$stabileData['database_dedicato']]);
|
||
echo \"🔄 Stabile {\$stabileData['codice_stabile']} aggiornato\\n\";
|
||
}
|
||
}
|
||
|
||
echo \"🎉 Restore record completato!\\n\";
|
||
|
||
} catch (Exception \$e) {
|
||
echo \"❌ Errore durante restore: \" . \$e->getMessage() . \"\\n\";
|
||
exit(1);
|
||
}
|
||
";
|
||
}
|
||
|
||
/**
|
||
* Crea README istruzioni migrazione
|
||
*/
|
||
private function createMigrationReadme(Amministratore $amministratore): string
|
||
{
|
||
return "# 📦 Migrazione Amministratore {$amministratore->codice_univoco}
|
||
|
||
## 📋 Informazioni Migrazione
|
||
- **Amministratore**: {$amministratore->nome_completo}
|
||
- **Studio**: {$amministratore->denominazione_studio}
|
||
- **Codice**: {$amministratore->codice_univoco}
|
||
- **Data Migrazione**: " . date('d/m/Y H:i') . "
|
||
- **Server Origine**: " . env('APP_URL') . "
|
||
|
||
## 🎯 Contenuto Package
|
||
- Database amministratore principale
|
||
- Database dedicati per ogni stabile
|
||
- Archivio completo filesystem
|
||
- Script automatici di restore
|
||
- Metadata e configurazioni
|
||
|
||
## 🚀 Procedura di Restore
|
||
|
||
### 1️⃣ Prerequisiti
|
||
```bash
|
||
# MySQL server attivo
|
||
# PHP 8.1+ con estensioni: zip, pdo_mysql, openssl
|
||
# Spazio disco sufficiente (vedere metadata.json)
|
||
# Accesso directory NetGescon
|
||
```
|
||
|
||
### 2️⃣ Configurazione Environment
|
||
```bash
|
||
export MYSQL_USER=\"root\"
|
||
export MYSQL_PASS=\"password\"
|
||
export MYSQL_HOST=\"localhost\"
|
||
export TARGET_PATH=\"/var/www/netgescon/storage/app/amministratori\"
|
||
```
|
||
|
||
### 3️⃣ Esecuzione Restore
|
||
```bash
|
||
# 1. Restore database
|
||
cd scripts/
|
||
chmod +x *.sh
|
||
./restore_databases.sh
|
||
|
||
# 2. Restore filesystem
|
||
./restore_filesystem.sh
|
||
|
||
# 3. Restore record Laravel
|
||
php restore_records.php
|
||
|
||
# 4. Verifica migrazione
|
||
./verify_migration.sh
|
||
```
|
||
|
||
## ⚠️ Note Importanti
|
||
|
||
### 🔐 Sicurezza
|
||
- Modificare password temporanee dopo restore
|
||
- Verificare permessi filesystem
|
||
- Testare connessioni database
|
||
|
||
### 🔄 Post-Migrazione
|
||
- Aggiornare configurazioni server-specific
|
||
- Verificare path assoluti
|
||
- Testare funzionalità complete
|
||
- Aggiornare backup automatici
|
||
|
||
### 🆘 Troubleshooting
|
||
- Verificare log errori in `/var/log/mysql/`
|
||
- Controllare permessi `www-data`
|
||
- Verificare spazio disco disponibile
|
||
- Consultare `verify_migration.sh`
|
||
|
||
## 📊 Statistiche Migrazione
|
||
- **Stabili Inclusi**: " . $amministratore->stabili->count() . "
|
||
- **Database**: " . ($amministratore->stabili->where('database_dedicato', '!=', null)->count() + 1) . "
|
||
- **Spazio Richiesto**: Vedere metadata.json
|
||
|
||
---
|
||
|
||
*Package generato automaticamente da NetGescon v2.1.0*
|
||
";
|
||
}
|
||
|
||
/**
|
||
* Verifica integrità migrazione
|
||
*/
|
||
private function verifyMigrationIntegrity(string $migrationPath): array
|
||
{
|
||
try {
|
||
$checks = [
|
||
'metadata_exists' => file_exists($migrationPath . '/metadata.json'),
|
||
'scripts_exists' => is_dir($migrationPath . '/scripts'),
|
||
'database_backups' => 0,
|
||
'filesystem_archives' => 0,
|
||
];
|
||
|
||
// Conta backup database
|
||
$files = glob($migrationPath . '/backup_*.sql');
|
||
$checks['database_backups'] = count($files);
|
||
|
||
// Conta archivi filesystem
|
||
$archives = glob($migrationPath . '/filesystem_*.zip');
|
||
$checks['filesystem_archives'] = count($archives);
|
||
|
||
$checks['integrity_ok'] = $checks['metadata_exists'] &&
|
||
$checks['scripts_exists'] &&
|
||
$checks['database_backups'] > 0;
|
||
|
||
return [
|
||
'success' => true,
|
||
'checks' => $checks,
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Crea package finale migrazione
|
||
*/
|
||
private function createMigrationPackage(string $migrationId, string $migrationPath): array
|
||
{
|
||
try {
|
||
$packagePath = storage_path("app/migrations/{$migrationId}.zip");
|
||
|
||
$zip = new ZipArchive();
|
||
if ($zip->open($packagePath, ZipArchive::CREATE) !== true) {
|
||
throw new Exception('Impossibile creare package migrazione');
|
||
}
|
||
|
||
$iterator = new \RecursiveIteratorIterator(
|
||
new \RecursiveDirectoryIterator($migrationPath, \RecursiveDirectoryIterator::SKIP_DOTS)
|
||
);
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isFile()) {
|
||
$relativePath = str_replace($migrationPath . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
||
$zip->addFile($file->getPathname(), $relativePath);
|
||
}
|
||
}
|
||
|
||
$zip->close();
|
||
|
||
// Rimuovi cartella temporanea
|
||
$this->deleteDirectory($migrationPath);
|
||
|
||
return [
|
||
'success' => true,
|
||
'package_path' => $packagePath,
|
||
'package_size' => filesize($packagePath),
|
||
'download_url' => url('admin/migrations/download/' . basename($packagePath)),
|
||
];
|
||
} catch (Exception $e) {
|
||
return [
|
||
'success' => false,
|
||
'error' => $e->getMessage(),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Calcola spazio richiesto
|
||
*/
|
||
private function calculateRequiredSpace(Amministratore $amministratore): int
|
||
{
|
||
$totalSize = 0;
|
||
|
||
// Dimensione archivio amministratore
|
||
$adminPath = $this->tenantArchivePath->amministratoreAbsolutePath($amministratore);
|
||
if (is_dir($adminPath)) {
|
||
$totalSize += $this->getDirectorySize($adminPath);
|
||
}
|
||
|
||
// Aggiungi overhead per backup database (stimato)
|
||
$totalSize += 50 * 1024 * 1024; // 50MB stimati per backup
|
||
|
||
return intval($totalSize / (1024 * 1024)); // Converti in MB
|
||
}
|
||
|
||
/**
|
||
* Analizza struttura cartelle
|
||
*/
|
||
private function analyzeFolderStructure(Amministratore $amministratore): array
|
||
{
|
||
$adminPath = $this->tenantArchivePath->amministratoreAbsolutePath($amministratore);
|
||
|
||
if (! is_dir($adminPath)) {
|
||
return ['exists' => false];
|
||
}
|
||
|
||
return [
|
||
'exists' => true,
|
||
'path' => $adminPath,
|
||
'size' => $this->getDirectorySize($adminPath),
|
||
'files_count' => $this->countFiles($adminPath),
|
||
'directories' => $this->listDirectories($adminPath),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Analizza struttura database
|
||
*/
|
||
private function analyzeDatabaseStructure(Amministratore $amministratore): array
|
||
{
|
||
$structure = [
|
||
'amministratore' => [
|
||
'database' => $amministratore->getDatabaseName(),
|
||
'exists' => false,
|
||
'tables' => [],
|
||
],
|
||
'stabili' => [],
|
||
];
|
||
|
||
// Verifica database amministratore
|
||
try {
|
||
$tables = DB::select("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ?", [$amministratore->getDatabaseName()]);
|
||
$structure['amministratore']['exists'] = count($tables) > 0;
|
||
$structure['amministratore']['tables'] = array_column($tables, 'TABLE_NAME');
|
||
} catch (Exception $e) {
|
||
// Database non esiste
|
||
}
|
||
|
||
// Verifica database stabili
|
||
foreach ($amministratore->stabili as $stabile) {
|
||
if ($stabile->database_dedicato) {
|
||
$stabileInfo = [
|
||
'codice' => $stabile->codice_stabile,
|
||
'database' => $stabile->database_dedicato,
|
||
'exists' => false,
|
||
'tables' => [],
|
||
];
|
||
|
||
try {
|
||
$tables = DB::select("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ?", [$stabile->database_dedicato]);
|
||
$stabileInfo['exists'] = count($tables) > 0;
|
||
$stabileInfo['tables'] = array_column($tables, 'TABLE_NAME');
|
||
} catch (Exception $e) {
|
||
// Database non esiste
|
||
}
|
||
|
||
$structure['stabili'][] = $stabileInfo;
|
||
}
|
||
}
|
||
|
||
return $structure;
|
||
}
|
||
|
||
/**
|
||
* Utilities
|
||
*/
|
||
private function getDirectorySize(string $path): int
|
||
{
|
||
$size = 0;
|
||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isFile()) {
|
||
$size += $file->getSize();
|
||
}
|
||
}
|
||
|
||
return $size;
|
||
}
|
||
|
||
private function countFiles(string $path): int
|
||
{
|
||
$count = 0;
|
||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isFile()) {
|
||
$count++;
|
||
}
|
||
}
|
||
|
||
return $count;
|
||
}
|
||
|
||
private function listDirectories(string $path): array
|
||
{
|
||
$directories = [];
|
||
$iterator = new \RecursiveIteratorIterator(
|
||
new \RecursiveDirectoryIterator($path),
|
||
\RecursiveIteratorIterator::SELF_FIRST
|
||
);
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isDir() && ! in_array($file->getFilename(), ['.', '..'])) {
|
||
$relativePath = str_replace($path . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
||
$directories[] = $relativePath;
|
||
}
|
||
}
|
||
|
||
return $directories;
|
||
}
|
||
|
||
private function deleteDirectory(string $path): bool
|
||
{
|
||
if (! is_dir($path)) {
|
||
return false;
|
||
}
|
||
|
||
$iterator = new \RecursiveIteratorIterator(
|
||
new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||
\RecursiveIteratorIterator::CHILD_FIRST
|
||
);
|
||
|
||
foreach ($iterator as $file) {
|
||
if ($file->isDir()) {
|
||
rmdir($file->getPathname());
|
||
} else {
|
||
unlink($file->getPathname());
|
||
}
|
||
}
|
||
|
||
return rmdir($path);
|
||
}
|
||
}
|