buildSourceCandidates($legacyCode, $sourceBasePath); $sourcePath = $this->resolveExistingDirectory($sourceCandidates); if (!$sourcePath) { throw new \RuntimeException('Archivio legacy non trovato per codice ' . $legacyCode); } // Assicura struttura cartelle amministratore $amministratore->provisionArchiveIfMissing(); $baseArchivePath = $amministratore->getArchivePath(); $this->ensureDirectoryExists($baseArchivePath); $targetPath = $baseArchivePath . DIRECTORY_SEPARATOR . 'legacy' . DIRECTORY_SEPARATOR . $legacyCode; $this->ensureDirectoryExists(dirname($targetPath)); if ($refresh && $this->isDirectory($targetPath)) { $this->deleteDirectory($targetPath); } // Copia solo se la directory non esiste oppure è stato richiesto refresh if (!$this->isDirectory($targetPath)) { $this->copyDirectory($sourcePath, $targetPath); } $meta = $this->inspectDirectory($targetPath); return [ 'legacy_code' => $legacyCode, 'source' => $sourcePath, 'target' => $targetPath, 'copied_at' => date('Y-m-d H:i:s'), 'size_bytes' => $meta['size'], 'files_count' => $meta['files_count'], 'directories_count' => $meta['directories_count'], 'latest_file_at' => $meta['latest_file_at'], ]; } private function buildSourceCandidates(string $legacyCode, string $basePath): array { $candidates = []; if ($basePath !== '') { $candidates[] = $basePath . DIRECTORY_SEPARATOR . $legacyCode; $candidates[] = $basePath . DIRECTORY_SEPARATOR . str_pad($legacyCode, 4, '0', STR_PAD_LEFT); } // In alcuni casi il legacy code include già l'intero percorso if ($this->isDirectory($legacyCode)) { $candidates[] = $legacyCode; } return array_values(array_unique(array_filter($candidates))); } private function resolveExistingDirectory(array $candidates): ?string { foreach ($candidates as $directory) { if ($directory && $this->isDirectory($directory)) { return rtrim($directory, DIRECTORY_SEPARATOR); } } return null; } private function ensureDirectoryExists(string $path): void { if (!$this->isDirectory($path)) { if (!mkdir($path, 0755, true) && !is_dir($path)) { throw new \RuntimeException('Impossibile creare directory: ' . $path); } } } private function deleteDirectory(string $path): void { if (!$this->isDirectory($path)) { return; } $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST ); foreach ($iterator as $item) { if ($item->isDir()) { rmdir($item->getPathname()); } else { unlink($item->getPathname()); } } rmdir($path); } private function copyDirectory(string $source, string $target): void { if (!$this->isDirectory($source)) { throw new \RuntimeException('Sorgente non valida: ' . $source); } $this->ensureDirectoryExists($target); $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($source, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $item) { $relativePath = ltrim(substr($item->getPathname(), strlen($source)), DIRECTORY_SEPARATOR); $destinationPath = $relativePath === '' ? $target : $target . DIRECTORY_SEPARATOR . $relativePath; if ($item->isDir()) { $this->ensureDirectoryExists($destinationPath); } else { $this->ensureDirectoryExists(dirname($destinationPath)); if (!copy($item->getPathname(), $destinationPath)) { throw new \RuntimeException('Impossibile copiare file: ' . $item->getPathname()); } } } } private function isDirectory(string $path): bool { return is_dir($path); } private function inspectDirectory(string $path): array { $size = 0; $files = 0; $dirs = 0; $latest = null; $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS) ); foreach ($iterator as $item) { if ($item->isDir()) { $dirs++; continue; } $files++; $size += $item->getSize(); $mtime = $item->getMTime(); if (!$latest || $mtime > $latest) { $latest = $mtime; } } return [ 'size' => $size, 'files_count' => $files, 'directories_count' => $dirs, 'latest_file_at' => $latest ? date('Y-m-d H:i:s', $latest) : null, ]; } }