I am trying to get the top of users and order them by popularity of their recipes
The popularity of a recipe is determined by the number of:
-
likes
-
dislikes
(likes and dislikes are stored in create_votes_table and showed in column vote with 1, -1, or 0 (like, neutral, dislike))
-
savings by users
(savings are stored in the create_saved_recipes_table and simply stores recipe_id of recipe and user_id of user who saved this Recipe)
it receives. If a user has multiple recipes,
these metrics are summed up to calculate the total number of likes,
dislikes, and saves across all their recipes. For example, if one
user has three recipes with 3, 2, and 5 likes, and another user has a single recipe with 15 likes, the second user will rank higher on the
list than the first.
If the first recipe has more likes than the second, but the second has more saves, the second is considered more popular. This means that saves carry more weight in the popularity statistics.
User.php
public function recipes(): HasMany
{
return $this->hasMany(Recipe::class);
}
Recipe.php
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function scopePopular(Builder $query): Builder
{
return $query->whereHas('votes', fn ($q) => $q->where('vote', 1))
->orWhereHas('savedByUsers')
->withCount([
'votes as likesCount' => fn (Builder $query) => $query->where('vote', 1),
'votes as dislikesCount' => fn (Builder $query) => $query->where('vote', -1),
'savedByUsers as savedCount',
])
->orderByDesc('savedCount')
->orderByDesc('likesCount')
->orderBy('dislikesCount')
->orderByDesc('created_at');
}
create_votes_table
Schema::create('votes', function (Blueprint $table) {
$table->id();
$table->foreignId('recipe_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->smallInteger('vote');
$table->timestamps();
});
create_saved_recipes_table
Schema::create('saved_recipes', function (Blueprint $table) {
$table->id();
$table->foreignId('recipe_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
I tried this approach:
$authorsOfTheWeek = User::select(['id','name', 'photo'])->withCount([
'recipes as recipe_popularity' => fn($query) => $query->popular()
])
->having('recipe_popularity', '>', 0)
->orderByDesc('recipe_popularity')
->get();
But now I can't order users by Recipe's popularity parameters
Would be grateful for your help
Best regards