where('is_active', true) ->get(); $triggered = 0; foreach ($alerts as $alert) { $currentValue = $this->getCurrentValue($alert); $shouldTrigger = $this->evaluate($alert, $currentValue); if ($shouldTrigger) { $this->trigger($alert, $currentValue); $triggered++; } } $this->info("Checked {$alerts->count()} alerts, triggered {$triggered}."); return self::SUCCESS; } private function getCurrentValue(Alert $alert): float { $to = Carbon::today(); $from = $alert->period === 'hourly' ? Carbon::now()->subHour() : Carbon::yesterday(); $service = AnalyticsQueryService::for($alert->website, $from, $to); $summary = $service->summary(); return match ($alert->metric) { 'page_views' => $summary['page_views'], 'visitors' => $summary['visitors'], 'sessions' => $summary['sessions'], 'bounce_rate' => $summary['bounce_rate'], default => 0, }; } private function evaluate(Alert $alert, float $currentValue): bool { return match ($alert->condition) { 'above' => $currentValue > $alert->threshold, 'below' => $currentValue < $alert->threshold, 'change_up' => $this->percentageChange($alert) > $alert->threshold, 'change_down' => $this->percentageChange($alert) < -$alert->threshold, default => false, }; } private function percentageChange(Alert $alert): float { $to = Carbon::today(); $from = Carbon::yesterday(); $prevFrom = Carbon::yesterday()->subDay(); $prevTo = Carbon::yesterday(); $current = $this->getValueForPeriod($alert, $from, $to); $previous = $this->getValueForPeriod($alert, $prevFrom, $prevTo); if ($previous == 0) { return $current > 0 ? 100 : 0; } return (($current - $previous) / $previous) * 100; } private function getValueForPeriod(Alert $alert, Carbon $from, Carbon $to): float { $service = AnalyticsQueryService::for($alert->website, $from, $to); $summary = $service->summary(); return $summary[$alert->metric] ?? 0; } private function trigger(Alert $alert, float $currentValue): void { $conditionLabel = Alert::$conditions[$alert->condition] ?? $alert->condition; $metricLabel = Alert::$metrics[$alert->metric] ?? $alert->metric; $message = "{$metricLabel} {$conditionLabel} {$alert->threshold} (current: {$currentValue}) for {$alert->website->name}"; $notification = $alert->notifications()->create([ 'value' => $currentValue, 'message' => $message, ]); $alert->update(['last_triggered_at' => now()]); if (in_array($alert->channel, ['email', 'both'])) { Mail::to($alert->website->user)->send(new AlertTriggered($alert, $notification)); } $this->line(" → Triggered: {$alert->name} — {$message}"); } }