'integer', 'cook_time' => 'integer', 'total_time' => 'integer', 'servings' => 'integer', 'calories' => 'integer', 'status' => 'integer', 'views_count' => 'integer', 'rating_avg' => 'decimal:2', 'rating_count' => 'integer', ]; public function ingredients(): BelongsToMany { return $this->belongsToMany(Ingredient::class, 'recipe_ingredient') ->withPivot('quantity', 'unit', 'notes', 'sort_order') ->withTimestamps() ->orderBy('recipe_ingredient.sort_order'); } public function steps(): HasMany { return $this->hasMany(RecipeStep::class)->orderBy('sort_order'); } public function images(): HasMany { return $this->hasMany(RecipeImage::class)->orderBy('sort_order'); } public function nutrition(): HasOne { return $this->hasOne(RecipeNutrition::class); } public function tags(): BelongsToMany { return $this->belongsToMany(Tag::class, 'recipe_tag')->withTimestamps(); } public function ratings(): HasMany { return $this->hasMany(RecipeRating::class); } public function comments(): HasMany { return $this->hasMany(RecipeComment::class)->latest(); } public function favoritedBy(): BelongsToMany { return $this->belongsToMany(User::class, 'user_favorites')->withTimestamps(); } public function isFavoritedBy(?User $user): bool { if (!$user) { return false; } return $this->favoritedBy()->where('user_id', $user->id)->exists(); } public function userRating(?User $user): ?int { if (!$user) { return null; } return $this->ratings()->where('user_id', $user->id)->value('rating'); } public function getRecipeImage() { if ($this->featured_image) { return $this->featured_image; } if ($this->images()) { return $this->images()->first()->image_path; } return null; } }