where('status', '!=', 'archived'); if ($slug = $this->option('slug')) { $query->where('slug', $slug); } $companies = $query->get(); if ($companies->isEmpty()) { $this->warn('No tenants to back up.'); return self::SUCCESS; } $date = date('Y-m-d'); $base = storage_path("app/backups/{$date}"); if (! is_dir($base)) @mkdir($base, 0775, true); $manager = app(TenantManager::class); $ok = 0; $failed = 0; foreach ($companies as $company) { try { $manager->setCurrent($company); app(\Spatie\Permission\PermissionRegistrar::class) ->setPermissionsTeamId($company->id); $tmp = $service->export($company); $dest = "{$base}/{$company->slug}.zip"; @rename($tmp, $dest); $size = round(filesize($dest) / 1024, 1); $this->info("✓ {$company->slug} → {$size}KB"); $ok++; } catch (\Throwable $e) { $this->error("✗ {$company->slug}: {$e->getMessage()}"); $failed++; } finally { $manager->setCurrent(null); } } $this->cleanupOld((int) $this->option('keep')); $this->newLine(); $this->info("Backup completed: {$ok} ok, {$failed} failed."); return $failed > 0 ? self::FAILURE : self::SUCCESS; } private function cleanupOld(int $keep): void { $backupsDir = storage_path('app/backups'); if (! is_dir($backupsDir)) return; $dates = collect(scandir($backupsDir)) ->filter(fn ($d) => preg_match('/^\d{4}-\d{2}-\d{2}$/', $d)) ->sortDesc() ->values(); $toDelete = $dates->slice($keep); foreach ($toDelete as $dateDir) { $abs = "{$backupsDir}/{$dateDir}"; if (is_dir($abs)) { array_map('unlink', glob("{$abs}/*")); @rmdir($abs); $this->line("Removed old backup: {$dateDir}"); } } } }