85 lines
2.5 KiB
PHP
85 lines
2.5 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace App\Console\Commands;
|
||
|
|
|
||
|
|
use App\Models\AnalyticsSession;
|
||
|
|
use App\Models\Event;
|
||
|
|
use App\Models\PageView;
|
||
|
|
use App\Models\Website;
|
||
|
|
use Illuminate\Console\Command;
|
||
|
|
use Illuminate\Support\Carbon;
|
||
|
|
|
||
|
|
class PurgeAnalytics extends Command
|
||
|
|
{
|
||
|
|
protected $signature = 'analytics:purge
|
||
|
|
{--website= : Purge only a specific website ID.}
|
||
|
|
{--force : Skip confirmation prompt.}';
|
||
|
|
|
||
|
|
protected $description = 'Delete raw analytics data older than each website\'s retention period';
|
||
|
|
|
||
|
|
private const DEFAULT_RETENTION_DAYS = 365;
|
||
|
|
|
||
|
|
public function handle(): int
|
||
|
|
{
|
||
|
|
$websites = $this->option('website')
|
||
|
|
? Website::where('id', $this->option('website'))->get()
|
||
|
|
: Website::all();
|
||
|
|
|
||
|
|
if ($websites->isEmpty()) {
|
||
|
|
$this->warn('No websites found.');
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
$summary = $websites->map(fn (Website $w) => [
|
||
|
|
'id' => $w->id,
|
||
|
|
'name' => $w->name,
|
||
|
|
'retention' => $this->getRetentionDays($w) . ' days',
|
||
|
|
'cutoff' => Carbon::today()->subDays($this->getRetentionDays($w))->toDateString(),
|
||
|
|
])->toArray();
|
||
|
|
|
||
|
|
$this->table(['ID', 'Website', 'Retention', 'Delete before'], $summary);
|
||
|
|
|
||
|
|
if (! $this->option('force') && ! $this->confirm('Proceed with purging old raw data?')) {
|
||
|
|
$this->info('Cancelled.');
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($websites as $website) {
|
||
|
|
$this->purgeForWebsite($website);
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->info('Purge complete.');
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function purgeForWebsite(Website $website): void
|
||
|
|
{
|
||
|
|
$retentionDays = $this->getRetentionDays($website);
|
||
|
|
$cutoff = Carbon::today()->subDays($retentionDays);
|
||
|
|
|
||
|
|
$this->info("Purging {$website->name} (data before {$cutoff->toDateString()})...");
|
||
|
|
|
||
|
|
$pvDeleted = PageView::where('website_id', $website->id)
|
||
|
|
->where('viewed_at', '<', $cutoff)
|
||
|
|
->delete();
|
||
|
|
|
||
|
|
$evDeleted = Event::where('website_id', $website->id)
|
||
|
|
->where('occurred_at', '<', $cutoff)
|
||
|
|
->delete();
|
||
|
|
|
||
|
|
$sessDeleted = AnalyticsSession::where('website_id', $website->id)
|
||
|
|
->where('started_at', '<', $cutoff)
|
||
|
|
->delete();
|
||
|
|
|
||
|
|
$this->line(" Deleted: {$pvDeleted} page views, {$evDeleted} events, {$sessDeleted} sessions");
|
||
|
|
}
|
||
|
|
|
||
|
|
private function getRetentionDays(Website $website): int
|
||
|
|
{
|
||
|
|
return $website->settings['data_retention_days'] ?? self::DEFAULT_RETENTION_DAYS;
|
||
|
|
}
|
||
|
|
}
|