toDateString(); // 1. Find all unique dates before today that have visits $dates = ShortUrlVisit::whereDate('visited_at', '<', $today) ->selectRaw('DATE(visited_at) as visit_date') ->distinct() ->pluck('visit_date') ->toArray(); if (empty($dates)) { $this->info('No historical visits to aggregate.'); } else { $this->info('Found ' . count($dates) . ' days to aggregate.'); foreach ($dates as $date) { // Find all visits on this day $visits = ShortUrlVisit::whereDate('visited_at', '=', $date)->get(); $visitsByUrl = $visits->groupBy('short_url_id'); foreach ($visitsByUrl as $urlId => $urlVisits) { $total = $urlVisits->count(); $unique = $urlVisits->unique('ip_hash')->count(); // Group helper $groupByField = function ($collection, $field) { return $collection->whereNotNull($field) ->groupBy($field) ->map(fn ($group) => $group->count()) ->toArray(); }; $deviceStats = $groupByField($urlVisits, 'device_type'); $browserStats = $groupByField($urlVisits, 'browser'); $osStats = $groupByField($urlVisits, 'operating_system'); // Country $countryStats = $urlVisits->whereNotNull('country') ->groupBy('country') ->map(fn ($group) => $group->count()) ->toArray(); // City $cityStats = $urlVisits->whereNotNull('city') ->map(function ($visit) { $visit->city_key = "{$visit->city} ({$visit->country_code})"; return $visit; }) ->groupBy('city_key') ->map(fn ($group) => $group->count()) ->toArray(); // Referer $refererStats = $urlVisits->whereNotNull('referer_host') ->groupBy('referer_host') ->map(fn ($group) => $group->count()) ->toArray(); // UTM $utmSourceStats = $groupByField($urlVisits, 'utm_source'); $utmMediumStats = $groupByField($urlVisits, 'utm_medium'); $utmCampaignStats = $groupByField($urlVisits, 'utm_campaign'); // Upsert into short_url_daily_stats ShortUrlDailyStats::updateOrCreate([ 'short_url_id' => $urlId, 'date' => $date, ], [ 'visits_count' => $total, 'unique_visits_count' => $unique, 'device_stats' => $deviceStats, 'browser_stats' => $browserStats, 'os_stats' => $osStats, 'country_stats' => $countryStats, 'city_stats' => $cityStats, 'referer_stats' => $refererStats, 'utm_source_stats' => $utmSourceStats, 'utm_medium_stats' => $utmMediumStats, 'utm_campaign_stats' => $utmCampaignStats, ]); } $this->info("Aggregated stats for {$date}."); } } // 2. Prune old visits if enabled if (config('filament-short-url.pruning.enabled', true)) { $retentionDays = (int) config('filament-short-url.pruning.retention_days', 90); $cutoff = Carbon::now()->subDays($retentionDays)->toDateTimeString(); $deleted = ShortUrlVisit::where('visited_at', '<', $cutoff)->delete(); $this->info("Successfully pruned {$deleted} raw visit records older than {$retentionDays} days."); } return 0; } }