*/ use HasFactory, HasAchievements, HasApiTokens, HasRoles, HasPushSubscriptions, Notifiable; protected $casts = [ 'email_verified_at' => 'datetime', 'password' => 'hashed', 'settings' => 'array', ]; protected $appends = ['resolved_settings']; public function calculateAchievementsAndClearCache(): void { $this->clearCache(); $this->calculateAchievements(); } public function clearCache(): void { Cache::forget("user_flights_{$this->id}"); $this ->followers() ->get() ->each(fn ($follower) => Cache::forget("user_following_flights_{$follower->id}")); } public function achievements(): HasMany { return $this->hasMany(UserAchievement::class); } public function getSetting(string $key): mixed { $defaults = SettingsRegistry::defaults(); return $this->settings[$key] ?? $defaults[$key] ?? null; } public function updateSettings(array $values): void { $current = array_merge(SettingsRegistry::defaults(), $this->settings ?? []); $this->update(['settings' => array_merge($current, $values)]); } function updateSetting($settingName, $value) : void{ $this->updateSettings([$settingName => $value]); } protected function resolvedSettings(): Attribute { return Attribute::make( get: fn() => array_merge(SettingsRegistry::defaults(), $this->settings ?? []) ); } public function unlockedAchievements(): HasMany { return $this->achievements() ->join('achievements', 'achievements.id', '=', 'user_achievements.achievement_id') ->where(function ($query) { $query // Non-progressive achievements: always count ->where(function ($q) { $q->where('achievements.progressive', false) ->orWhereNull('achievements.progressive'); }) // Progressive achievements: only if progress >= threshold ->orWhere(function ($q) { $q->where('achievements.progressive', true) ->whereNotNull('achievements.threshold') ->whereColumn('user_achievements.progress', '>=', 'achievements.threshold'); }); }); } public function sendPasswordResetNotification($token): void { $this->notify(new ResetPasswordNotification($token)); } public function resolveRouteBinding($value, $field = null): ?User { return $this->where('name', 'ilike', $value)->firstOrFail(); } public function flights(): HasMany { return $this->hasMany(UserFlight::class); } public function departedFlights() : HasMany { return $this->flights()->where('departure_date', '<=', now('UTC')); } public function upcomingFlights() : HasMany { return $this->flights()->where('departure_date', '>=', now('UTC')); } public function flightsWithRelationshipsLoaded(?string $filter = null): Collection { $key = "user_flights_{$this->id}"; $json = Cache::remember($key, now()->addDays(30), function () { return $this->flights() ->with([ 'departureAirport.region.country', 'departureAirport.region.continent', 'arrivalAirport.region.country', 'arrivalAirport.region.continent', 'airline.country', 'airline.alliance', 'aircraft', 'seatType', 'flightReason', 'flightClass', 'crewType' ]) ->orderBy('departure_date', 'desc') ->get() ->values() ->toJson(); }); $collection = collect(json_decode($json)); $today = now('UTC')->toDateString(); return match ($filter) { 'departed' => $collection->filter(fn($f) => Carbon::parse($f->departure_date)->toDateString() <= $today)->values(), 'upcoming' => $collection->filter(fn($f) => Carbon::parse($f->departure_date)->toDateString() > $today)->values(), default => $collection, }; } public function ImportedFlights(): HasMany { return $this->hasMany(ImportedFlight::class); } public function following(): HasMany { return $this->hasMany(Followee::class, 'user_id')->verified(); } public function pendingFollowers(): BelongsToMany { return $this->belongsToMany(User::class, 'followees', 'followee_id', 'user_id') ->withPivot('verified') ->wherePivot('verified', false) ->withTimestamps(); } public function followers(): BelongsToMany { return $this->belongsToMany(User::class, 'followees', 'followee_id', 'user_id') ->withPivot('verified') ->wherePivot('verified', true) ->withTimestamps(); } public function isFollowing(User $user): bool { return $this->following() ->where('followee_id', $user->id) ->exists(); } public function followStatus(User $user): string { $followee = $this->following()->where('followee_id', $user->id)->first(); if (!$followee) { return 'none'; } return $followee->verified ? 'following' : 'requested'; } public function notifications(): HasMany { return $this->hasMany(Notification::class); } }