Files
gamelog/app/Models/Game.php
T
MarkandClaude Sonnet 4.6 14047dfe37 Add friend library comparison and game comments features
- CompareController: side-by-side library diff with stats (common games, rating diff)
- GameCommentController + GameCommentPolicy: threaded comments with replies, auth-gated
- GameComment model with top-level scope and self-referential replies relation
- Migration: game_comments table with parent_id for threading
- games/show: Discussion section with Alpine.js (post, reply, delete)
- compare/show: tabbed view (in common, they have, you have) with game cards
- users/show: "Compare Libraries" button visible to other authenticated users

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 12:04:24 +03:00

96 lines
2.4 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cache;
use Laravel\Scout\Searchable;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
class Game extends Model
{
use HasSlug, Searchable;
protected $fillable = [
'igdb_id', 'slug', 'title', 'summary', 'cover_url', 'cover_thumb_url',
'release_date', 'release_year', 'rating_avg', 'rating_count', 'review_count',
'library_count', 'status',
];
protected $casts = [
'release_date' => 'date',
'rating_avg' => 'decimal:2',
];
public function getSlugOptions(): SlugOptions
{
return SlugOptions::create()->generateSlugsFrom('title')->saveSlugsTo('slug');
}
public function getRouteKeyName(): string { return 'slug'; }
public function genres(): BelongsToMany
{
return $this->belongsToMany(Genre::class, 'game_genre');
}
public function platforms(): BelongsToMany
{
return $this->belongsToMany(Platform::class, 'game_platform');
}
public function companies(): BelongsToMany
{
return $this->belongsToMany(Company::class, 'game_company')->withPivot('role');
}
public function screenshots(): HasMany
{
return $this->hasMany(GameScreenshot::class)->orderBy('order');
}
public function userGames(): HasMany
{
return $this->hasMany(UserGame::class);
}
public function reviews(): HasMany
{
return $this->hasMany(Review::class)->latest();
}
public function comments(): HasMany
{
return $this->hasMany(GameComment::class);
}
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'summary' => $this->summary,
];
}
public function scopePublished($query)
{
return $query->where('status', 'published');
}
public function recalculateRating(): void
{
$stats = $this->userGames()->whereNotNull('rating')->selectRaw('AVG(rating) as avg, COUNT(*) as cnt')->first();
$this->update([
'rating_avg' => $stats->avg ? round($stats->avg, 2) : null,
'rating_count' => $stats->cnt ?? 0,
]);
Cache::forget('home.top_rated');
Cache::forget('games.top_rated.1');
}
}