option('days') ?? config('conversion.events.retention_days')); if ($days < 1) { $this->error('Aufbewahrungszeitraum muss mindestens einen Tag betragen.'); return self::FAILURE; } $cutoff = now()->subDays($days); $chunk = max(100, (int) $this->option('chunk')); $expired = ConversionEvent::query()->where('created_at', '<', $cutoff); $bounceDays = max(1, (int) config('bounces.retention_days', 395)); $bounceCutoff = now()->subDays($bounceDays); $expiredBounces = EmailBounce::query()->where('created_at', '<', $bounceCutoff); if ($this->option('dry-run')) { $this->info(sprintf( '[Dry-Run] %d Ereignisse älter als %s.', (clone $expired)->count(), $cutoff->format('d.m.Y'), )); $this->info(sprintf( '[Dry-Run] %d Rückläufer-Ereignisse älter als %s.', (clone $expiredBounces)->count(), $bounceCutoff->format('d.m.Y'), )); return self::SUCCESS; } $deleted = 0; while (true) { $removed = (clone $expired)->limit($chunk)->delete(); if ($removed === 0) { break; } $deleted += $removed; } $this->info(sprintf( 'Konversions-Ereignisse bereinigt: %d Einträge vor dem %s gelöscht (Aufbewahrung %d Tage).', $deleted, $cutoff->format('d.m.Y'), $days, )); $bouncesDeleted = 0; while (true) { $removed = (clone $expiredBounces)->limit($chunk)->delete(); if ($removed === 0) { break; } $bouncesDeleted += $removed; } $this->info(sprintf( 'Rückläufer-Ereignisse bereinigt: %d Einträge vor dem %s gelöscht (Aufbewahrung %d Tage, Sperrliste bleibt).', $bouncesDeleted, $bounceCutoff->format('d.m.Y'), $bounceDays, )); return self::SUCCESS; } }