Hello
I have logic for like/dislike button in two separate livewire components
The problem is I want it to optimize db requests
At this moment after clicking like/dislike buttons I am getting 5-6 db queries:
select * from `sessions` where `id` = '...' limit 1
select * from `recipes` where `recipes`.`id` = 1 limit 1
select * from `users` where `id` = 1 limit 1
select exists(select * from `likes` where `likes`.`user_id` = 1 and `likes`.`user_id` is not null and (`recipe_id` = 1 and `liked` = 1)) as `exists`
select * from `likes` where `likes`.`recipe_id` = 1 and `likes`.`recipe_id` is not null and (`user_id` = 1) limit 1
insert into `likes` (`user_id`, `liked`, `recipe_id`, `updated_at`, `created_at`) values (1, 1, 1, '2025-05-09 05:28:38', '2025-05-09 05:28:38')
Code:
LikeButton.php:
class LikeButton extends Component
{
public Recipe $recipe;
public function toggleLike(): bool
{
// Check if user is authenticated
if (auth()->guest()){
return $this->redirect(route('login-page'));
}
// Get authenticated user
$user = auth()->user();
// Check if user has already liked recipe
// if true, then return unlike()
$hasLiked = $user->likes()->where([
'recipe_id' => $this->recipe->id,
'liked' => true
])->exists();
if ($hasLiked){
return $this->recipe->unlikeBy($user);
}
// return like()
return $this->recipe->likeBy($user);
}
// render() is empty
}
DislikeButton.php:
class DislikeButton extends Component
{
public Recipe $recipe;
public function toggleDislike(): bool
{
// Check if user is authenticated
if (auth()->guest()){
return $this->redirect(route('login-page'));
}
// Get authenticated user
$user = auth()->user();
// Check if user has already disliked recipe
// if true, then return undislike()
$hasDisliked = $user->likes()->where([
'recipe_id' => $this->recipe->id,
'liked' => false
])->exists();
if ($hasDisliked){
return $this->recipe->undislikeBy($user);
}
// return dislikeBy()
return $this->recipe->dislikeBy($user);
}
// render() is empty
}
As you see there is some duplication at the moment when we're getting auth user.
Would be grateful for some help
EDIT 01
Likable.php (trait for model Recipe.php)
trait Likable
{
public function likeBy($user = null, $liked = true): bool
{
return (bool) $this->likes()->updateOrCreate(
[
'user_id' => $user ? $user->id : auth()->id()
],
[
'liked' => $liked
]
);
}
public function dislikeBy($user = null): bool
{
return $this->likeBy($user, false);
}
public function unlikeBy($user = null, $liked = true): bool
{
return (bool) $this->likes()
->where([
'user_id' => $user ? $user->id : auth()->id(),
'recipe_id' => $this->id,
'liked' => $liked
])
->delete();
}
public function undislikeBy($user = null): bool
{
return $this->unlikeBy($user, false);
}
public function isLikedBy(User $user, $liked = true): bool
{
return (bool) $user->likes
->where([
'recipe_id' => $this->id,
'liked' => $liked
])
->count();
}
public function isDislikedBy(User $user): bool
{
return $this->isLikedBy($user, false);
}
public function likes(): HasMany
{
return $this->hasMany(Like::class);
}
}