Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bbmrw's avatar
Level 1

Problem with storing duplicate values in database with polymorphic relations in Laravel

I have favorites functionality with polymorphic one to many relations in Laravel. I have ProfileImages, PostImages and Favorites models as well as those three tables. When for example I store post image with id 1 in favorites table it looks like this

id   user_id   favoritable_id   favoritable_type
1       15           1          App\Models\PostImage

(favoritable_id is id of post image in post_images table)

And then if I go and store another post image with the id 1, my code as it is, will return message "You already favorited this post image!" but it will store that in favorites table regardless and I need it not to. I need some way to check both favoritable_id and favoritable_type to be unique together in order this to work. If only one of them is unique and other ins't it won't work as it should. I got favoritable_id to be like that, but I can't figure out favoritable_type (I get null value). I tried this way if someone can help me or if there is some other way any help would be appreciated. Here is my code.

web.php

Route::post('/post/image/{postimage}/favorite', [\App\Http\Controllers\FavoritesController::class, 'postImageFavorite'])->name('post-image-favorite');

Controller

public function postImageFavorite(FavoriteRequest $request, PostImage $image, $postimage)
{
	if($request->favorite == true) {
		if(PostImage::where('id', $postimage)->first()) {
		    $favorite = new Favorite();
	    	$favorite->user_id = $request->user()->id;
		    $favorite->favoritable_type	 = $image->getMorphClass();
		    $favorite->favoritable_id	 = $postimage;
		    $favorite->save(); 

		    // HERE IS CODE FOR DUPLICATE, THAT I TRIED
		    $checkForDuplicate1 = Favorite::where('favoritable_id', $postimage)->exists();
		    $checkForDuplicate2 = Favorite::where('favoritable_type', $favorite->favoritable_type)->exists();
		    if($checkForDuplicate1 && $checkForDuplicate2) {
				return response()->json([
			    	'message' => 'You already favorited this post image!'
				]);
		    }
		    
		     	
	    } else {
	    	return response()->json([
			    'message' => 'Post image doesn\'t exist!'
			]);
	    }

		$user = Auth::user();
        $model = Favorite::find($favorite->id);
		$id = $model->favoritable->post->user_profile_id;
        $other_user = User::findOrFail($id);
        $other_user->notify(new NewPostImageFavorite($user));

    } elseif($request->favorite == false) {
		$result = Favorite::where('user_id', auth()->user()->id)
            ->where('favoritable_id', $postimage)
            ->delete();

		return $result;
    }

    return response()->noContent();
}

PostImage.php

public function favorites()
{
    return $this->morphMany(Favorite::class, 'favoritable');
}

Favorites.php

public function favoritable()
{
	return $this->morphTo();
}
0 likes
5 replies
Tray2's avatar

There are two thing you can do. Make the combination between user_id and image_id unique in your migration. Then you should validate the the request and make sure that it's unique.

1 like
bbmrw's avatar
Level 1

Can you show me an example? I am not sure how to make the combination, what exactly do you mean?

Tray2's avatar

Here is an example on a validation that checks the uniqueness of two fields.

Validation in your controller

 $rules = [
            'user_id' => 'required|unique:image_users,'user_id,' . null . ',id,image_id,'. $this->image_id,
            'image_id' => 'required',
        ];

And in your database migration

$table->unique(['image_id', 'user_id']);
1 like
bbmrw's avatar
Level 1

I don't have image_users table. I have favorites table and post images table. user_id I have in favorites table.

Please or to participate in this conversation.