'array', 'platforms' => 'array', 'is_featured' => 'boolean', 'featured_until' => 'datetime', 'is_sponsored' => 'boolean', 'sponsor_until' => 'datetime', ]; public function category() { return $this->belongsTo(Category::class); } public function tags() { return $this->belongsToMany(Tag::class)->withPivot('sort')->withTimestamps(); } public function comments() { return $this->hasMany(Comment::class, 'target_id') ->where('target_type', 'product'); } public function scopePublished($query) { return $query->where('status', 'published'); } public function scopeFeatured($query) { return $query->where('is_featured', true) ->where(function ($inner) { $inner->whereNull('featured_until') ->orWhere('featured_until', '>=', now()); }); } public function getEffectiveHotScoreAttribute(): int { return $this->hot_override ?? $this->hot_score; } public function refreshHotScore(): void { $this->hot_score = $this->calculateHotScore(); $this->save(); } private function calculateHotScore(): int { if ($this->hot_override !== null) { return (int) $this->hot_override; } $weightView = (int) SiteSetting::value('hot_weight_view', 1); $weightClick = (int) SiteSetting::value('hot_weight_click', 3); return (int) $this->view_count * $weightView + (int) $this->click_count * $weightClick; } protected static function booted() { static::saving(function (Product $product): void { $product->hot_score = $product->calculateHotScore(); }); } }