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

MahmoudMonem's avatar

Trying to validate / prevent user from submitting multiple reviews for the same product

I have 3 tables Users | Products | Reviews

in my reviews table I have user_id and product_id

Once a user purchase specific product, he/she can submit review .. I am trying to prevent duplicated reviews for the same user. and I did the following to achieve that ..

1- in my "make_reviews_table.php"

            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->unsignedBigInteger('product_id');
            $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');

            $table->unique(['product_id', 'user_id']);

This actually prevents users from submitting a second review for the same product, but it throws a Database Error in the view and I don't want customers to see that .. so I tried to add this line in the controller [ even though I was so sure it's missing something

2- added conditional if before processing the review submission

    public function store(Request $request)
    {
   
        $findReview = Review::where('user_id', Auth::user()->id)->first();
        if($findReview) {
            return back()->with('error', 'You already reviewed this product');
        }else{

            Review::create($request->all());
        
            return redirect()->back()->with('success', 'Review Submitted Successfuly');

        }
       
    }

The problem here, which I knew, is that it prevents users from adding any other reviews on any other product. so I need to define "the current specific product" in the function. Or maybe there is something else better than this approach .. would appreciate your input.

Ps: my view url looks like .. website.com/{product-slug}

0 likes
7 replies
automica's avatar
automica
Best Answer
Level 54

@mahmoudmonem if you want to check for an existing review, you'll also want to pass in the product_id

$findReview = Review::where(['user_id' => Auth::user()->id, 'product_id' => $request->product_id])->first();
2 likes
MichalOravec's avatar

@mahmoudmonem Use firstOrCreate for that

public function store(Request $request)
{
    $review = Review::firstOrCreate([
        'user_id' => auth()->id(),
	'product_id' => $request->product_id
    ], $request->except('product_id'));

    if ($review->wasRecentlyCreated) {
        return back()->with('success', 'Review Submitted Successfuly');
    }

    return back()->with('error', 'You already reviewed this product');
}

Docs: https://laravel.com/docs/8.x/eloquent#firstorcreate-firstornew

1 like
automica's avatar

@michaloravec minor correction to yours:

'product_id' => $request->product_id

not

'product_id' => $reques->product_id
MahmoudMonem's avatar

Very interesting .. thanks @michaloravec for sharing .. I was wondering if there are any pros or cons for one approach over the other

    public function store(Request $request)
    {
$findReview = Review::where(['user_id' => Auth::user()->id, 'product_id' => $request->product_id])->first();
        if($findReview) {return back()->with('error', 'You already reviewed this product');}
        else{Review::create($request->all());
        return redirect()->back()->with('success', 'Review Submitted Successfuly');}
       
    }
MichalOravec's avatar

They do same thing, but your code is mess.

By the way in this case else is not neccessary. Do you know why?

Please or to participate in this conversation.