399 lines
12 KiB
PHP
399 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany; // Aggiunto per condomini()
|
|
use Illuminate\Database\Eloquent\SoftDeletes; // Aggiunto per soft deletes
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class Amministratore extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
/**
|
|
* The table associated with the model.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $table = 'amministratori';
|
|
// Rimossa la primaryKey personalizzata - usa 'id' standard Laravel
|
|
/**
|
|
* The attributes that are mass assignable.
|
|
*
|
|
* @var array<int, string>
|
|
*/
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'nome',
|
|
'cognome',
|
|
'denominazione_studio',
|
|
'partita_iva',
|
|
'codice_fiscale_studio',
|
|
'indirizzo_studio',
|
|
'cap_studio',
|
|
'citta_studio',
|
|
'provincia_studio',
|
|
'telefono_studio',
|
|
'email_studio',
|
|
'pec_studio',
|
|
'codice_amministratore',
|
|
];
|
|
|
|
/**
|
|
* Get the user associated with the Amministratore.
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'user_id');
|
|
}
|
|
|
|
/**
|
|
* Get the condomini for the Amministratore.
|
|
*/
|
|
public function stabili(): HasMany
|
|
{
|
|
return $this->hasMany(Stabile::class, 'amministratore_id', 'id');
|
|
}
|
|
/**
|
|
* Get the fornitori for the Amministratore.
|
|
*/
|
|
public function fornitori(): HasMany
|
|
{
|
|
return $this->hasMany(Fornitore::class, 'amministratore_id', 'id');
|
|
}
|
|
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
static::creating(function ($amministratore) {
|
|
if (empty($amministratore->codice_amministratore)) {
|
|
do {
|
|
$code = Str::upper(Str::random(8));
|
|
} while (self::where('codice_amministratore', $code)->exists());
|
|
$amministratore->codice_amministratore = $code;
|
|
}
|
|
});
|
|
|
|
// Auto-crea cartelle dopo la creazione
|
|
static::created(function ($amministratore) {
|
|
$amministratore->createFolderStructure();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Crea la struttura di cartelle per l'amministratore
|
|
*/
|
|
public function createFolderStructure(): void
|
|
{
|
|
$basePath = "amministratori/{$this->codice_univoco}";
|
|
|
|
$folders = [
|
|
'documenti/allegati',
|
|
'documenti/contratti',
|
|
'documenti/assemblee',
|
|
'documenti/preventivi',
|
|
'backup/database',
|
|
'backup/files',
|
|
'temp/upload',
|
|
'temp/processing',
|
|
'logs',
|
|
'exports',
|
|
];
|
|
|
|
foreach ($folders as $folder) {
|
|
Storage::disk('local')->makeDirectory("{$basePath}/{$folder}");
|
|
}
|
|
|
|
// Crea file README informativo
|
|
$readme = "# Cartella Amministratore: {$this->nome_completo}\n\n";
|
|
$readme .= "**Codice**: {$this->codice_amministratore}\n";
|
|
$readme .= "**Creato**: " . $this->created_at->format('d/m/Y H:i') . "\n\n";
|
|
$readme .= "## Struttura Cartelle\n\n";
|
|
$readme .= "- `documenti/` - Documenti dell'amministratore\n";
|
|
$readme .= "- `backup/` - Backup automatici\n";
|
|
$readme .= "- `temp/` - File temporanei\n";
|
|
$readme .= "- `logs/` - Log specifici\n";
|
|
$readme .= "- `exports/` - Esportazioni dati\n";
|
|
|
|
Storage::disk('local')->put("{$basePath}/README.md", $readme);
|
|
}
|
|
|
|
/**
|
|
* Ottieni il path della cartella dell'amministratore
|
|
*/
|
|
public function getFolderPath(): string
|
|
{
|
|
return "amministratori/{$this->codice_amministratore}";
|
|
}
|
|
|
|
/**
|
|
* Genera codice univoco alfanumerico 8 caratteri
|
|
*/
|
|
public function generateCodiceUnivoco(): string
|
|
{
|
|
do {
|
|
$codice = 'ADM' . strtoupper(substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, 5));
|
|
} while (self::where('codice_amministratore', $codice)->exists());
|
|
|
|
return $codice;
|
|
}
|
|
|
|
/**
|
|
* Verifica se l'amministratore ha un database dedicato attivo
|
|
*/
|
|
public function hasDedicatedDatabase(): bool
|
|
{
|
|
return !empty($this->database_attivo);
|
|
}
|
|
|
|
/**
|
|
* Ottiene il nome del database dedicato per questo amministratore
|
|
*/
|
|
public function getDatabaseName(): string
|
|
{
|
|
return $this->database_attivo ?: "netgescon_{$this->codice_amministratore}";
|
|
}
|
|
|
|
/**
|
|
* Ottiene il percorso fisico dell'archivio amministratore
|
|
*/
|
|
public function getArchivePath(): string
|
|
{
|
|
return storage_path("app/amministratori/{$this->codice_amministratore}");
|
|
}
|
|
|
|
/**
|
|
* Ottiene il percorso del backup database
|
|
*/
|
|
public function getDatabaseBackupPath(): string
|
|
{
|
|
return $this->getArchivePath() . '/backup/database';
|
|
}
|
|
|
|
/**
|
|
* Verifica se l'archivio fisico esiste
|
|
*/
|
|
public function archiveExists(): bool
|
|
{
|
|
return is_dir($this->getArchivePath());
|
|
}
|
|
|
|
/**
|
|
* Ottiene informazioni dettagliate sull'archivio
|
|
*/
|
|
public function getArchiveInfo(): array
|
|
{
|
|
$archivePath = $this->getArchivePath();
|
|
|
|
if (!$this->archiveExists()) {
|
|
return [
|
|
'exists' => false,
|
|
'path' => $archivePath,
|
|
'size' => 0,
|
|
'files_count' => 0,
|
|
'last_backup' => null
|
|
];
|
|
}
|
|
|
|
$size = 0;
|
|
$filesCount = 0;
|
|
$lastBackup = null;
|
|
|
|
// Calcola dimensione totale e numero file
|
|
$iterator = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($archivePath)
|
|
);
|
|
|
|
foreach ($iterator as $file) {
|
|
if ($file->isFile()) {
|
|
$size += $file->getSize();
|
|
$filesCount++;
|
|
|
|
// Trova ultimo backup database
|
|
if (str_contains($file->getPathname(), 'backup/database') &&
|
|
str_ends_with($file->getFilename(), '.sql')) {
|
|
$backupTime = filemtime($file->getPathname());
|
|
if (!$lastBackup || $backupTime > $lastBackup) {
|
|
$lastBackup = $backupTime;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return [
|
|
'exists' => true,
|
|
'path' => $archivePath,
|
|
'size' => $size,
|
|
'size_formatted' => $this->formatBytes($size),
|
|
'files_count' => $filesCount,
|
|
'last_backup' => $lastBackup ? date('Y-m-d H:i:s', $lastBackup) : null,
|
|
'directories' => [
|
|
'documenti' => is_dir($archivePath . '/documenti'),
|
|
'backup' => is_dir($archivePath . '/backup'),
|
|
'temp' => is_dir($archivePath . '/temp'),
|
|
'logs' => is_dir($archivePath . '/logs'),
|
|
'exports' => is_dir($archivePath . '/exports'),
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Formatta bytes in formato leggibile
|
|
*/
|
|
private function formatBytes(int $bytes, int $precision = 2): string
|
|
{
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
|
|
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
|
|
$bytes /= 1024;
|
|
}
|
|
|
|
return round($bytes, $precision) . ' ' . $units[$i];
|
|
}
|
|
|
|
/**
|
|
* Crea backup del database amministratore
|
|
*/
|
|
public function createDatabaseBackup(): array
|
|
{
|
|
try {
|
|
if (!$this->hasDedicatedDatabase()) {
|
|
throw new \Exception('Amministratore non ha database dedicato');
|
|
}
|
|
|
|
$backupPath = $this->getDatabaseBackupPath();
|
|
if (!is_dir($backupPath)) {
|
|
mkdir($backupPath, 0755, true);
|
|
}
|
|
|
|
$filename = "backup_" . $this->codice_amministratore . "_" . date('Y-m-d_H-i-s') . ".sql";
|
|
$fullPath = $backupPath . '/' . $filename;
|
|
|
|
$dbName = $this->getDatabaseName();
|
|
$command = sprintf(
|
|
'mysqldump -h %s -u %s -p%s %s > %s',
|
|
env('DB_HOST', '127.0.0.1'),
|
|
env('DB_USERNAME'),
|
|
env('DB_PASSWORD'),
|
|
escapeshellarg($dbName),
|
|
escapeshellarg($fullPath)
|
|
);
|
|
|
|
exec($command, $output, $returnCode);
|
|
|
|
if ($returnCode !== 0) {
|
|
throw new \Exception('Errore durante backup database: ' . implode("\n", $output));
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'filename' => $filename,
|
|
'path' => $fullPath,
|
|
'size' => filesize($fullPath),
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prepara archivio per migrazione/trasferimento
|
|
*/
|
|
public function prepareForMigration(): array
|
|
{
|
|
try {
|
|
// 1. Backup database
|
|
$dbBackup = $this->createDatabaseBackup();
|
|
if (!$dbBackup['success']) {
|
|
throw new \Exception('Errore backup database: ' . $dbBackup['error']);
|
|
}
|
|
|
|
// 2. Crea archivio ZIP dell'intera cartella
|
|
$archivePath = $this->getArchivePath();
|
|
$zipFilename = "migration_" . $this->codice_amministratore . "_" . date('Y-m-d_H-i-s') . ".zip";
|
|
$zipPath = storage_path("app/migrations/{$zipFilename}");
|
|
|
|
if (!is_dir(dirname($zipPath))) {
|
|
mkdir(dirname($zipPath), 0755, true);
|
|
}
|
|
|
|
$zip = new \ZipArchive();
|
|
if ($zip->open($zipPath, \ZipArchive::CREATE) !== TRUE) {
|
|
throw new \Exception('Impossibile creare archivio ZIP');
|
|
}
|
|
|
|
$iterator = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($archivePath)
|
|
);
|
|
|
|
foreach ($iterator as $file) {
|
|
if ($file->isFile()) {
|
|
$relativePath = str_replace($archivePath . DIRECTORY_SEPARATOR, '', $file->getPathname());
|
|
$zip->addFile($file->getPathname(), $relativePath);
|
|
}
|
|
}
|
|
|
|
$zip->close();
|
|
|
|
// 3. Crea file metadata per migrazione
|
|
$metadata = [
|
|
'amministratore' => [
|
|
'codice' => $this->codice_amministratore,
|
|
'nome' => $this->nome,
|
|
'cognome' => $this->cognome,
|
|
'denominazione_studio' => $this->denominazione_studio,
|
|
'database_name' => $this->getDatabaseName(),
|
|
],
|
|
'migration' => [
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'source_server' => env('APP_URL'),
|
|
'database_backup' => $dbBackup['filename'],
|
|
'archive_size' => filesize($zipPath),
|
|
'files_count' => $this->getArchiveInfo()['files_count'],
|
|
],
|
|
'requirements' => [
|
|
'php_version' => PHP_VERSION,
|
|
'laravel_version' => app()->version(),
|
|
'mysql_version' => DB::select('SELECT VERSION() as version')[0]->version,
|
|
]
|
|
];
|
|
|
|
$metadataPath = dirname($zipPath) . "/metadata_{$this->codice_amministratore}.json";
|
|
file_put_contents($metadataPath, json_encode($metadata, JSON_PRETTY_PRINT));
|
|
|
|
return [
|
|
'success' => true,
|
|
'zip_file' => $zipPath,
|
|
'metadata_file' => $metadataPath,
|
|
'size' => filesize($zipPath),
|
|
'database_backup' => $dbBackup['filename']
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attributo computed per nome completo
|
|
*/
|
|
public function getNomeCompletoAttribute(): string
|
|
{
|
|
return trim($this->nome . ' ' . $this->cognome);
|
|
}
|
|
} |