Product Review & Rating Laravel API

Product Review & Rating Laravel API

 Product Review & Rating Laravel API 

1️⃣ Database Migration

product_reviews table

php artisan make:migration create_product_reviews_table

Schema::create('product_reviews', function (Blueprint $table) { $table->id(); $table->foreignId('product_id')->constrained()->cascadeOnDelete(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->tinyInteger('rating')->unsigned(); // 1–5 $table->text('review')->nullable(); $table->timestamps(); $table->unique(['product_id', 'user_id']); // prevent duplicate });

2️⃣ Model

ProductReview.php

class ProductReview extends Model
{
    protected $fillable = [
        'product_id',
        'user_id',
        'rating',
        'review',
    ];

    protected $casts = [
        'rating' => 'integer',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}

3️⃣ Product Model Relation

public function reviews()
{
    return $this->hasMany(ProductReview::class);
}

public function averageRating()
{
    return $this->reviews()->avg('rating');
}

4️⃣ API Routes

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/products/{product}/reviews', [ProductReviewController::class, 'store']);
    Route::put('/products/{product}/reviews', [ProductReviewController::class, 'update']);
    Route::delete('/products/{product}/reviews', [ProductReviewController::class, 'destroy']);
});

Route::get('/products/{product}/reviews', [ProductReviewController::class, 'index']);

5️⃣ Controller

ProductReviewController.php

class ProductReviewController extends Controller
{
    // 📌 List reviews
    public function index(Product $product)
    {
        $reviews = ProductReview::with('user:id,name')
            ->where('product_id', $product->id)
            ->latest()
            ->get();

        return response()->json([
            'average_rating' => round($product->reviews()->avg('rating'), 2),
            'total_reviews'  => $reviews->count(),
            'reviews'        => $reviews
        ]);
    }

    // 📌 Store review
    public function store(Request $request, Product $product)
    {
        $request->validate([
            'rating' => 'required|integer|min:1|max:5',
            'review' => 'nullable|string'
        ]);

        $review = ProductReview::updateOrCreate(
            [
                'product_id' => $product->id,
                'user_id' => Auth::id()
            ],
            [
                'rating' => $request->rating,
                'review' => $request->review
            ]
        );

        return response()->json([
            'status'  => 'success',
            'message' => 'Review submitted successfully',
            'data'    => $review
        ], 201);
    }

    // 📌 Update review
    public function update(Request $request, Product $product)
    {
        $request->validate([
            'rating' => 'required|integer|min:1|max:5',
            'review' => 'nullable|string'
        ]);

        $review = ProductReview::where('product_id', $product->id)
            ->where('user_id', Auth::id())
            ->firstOrFail();

        $review->update($request->only('rating', 'review'));

        return response()->json([
            'status' => 'success',
            'message' => 'Review updated',
            'data' => $review
        ]);
    }

    // 📌 Delete review
    public function destroy(Product $product)
    {
        ProductReview::where('product_id', $product->id)
            ->where('user_id', Auth::id())
            ->delete();

        return response()->json([
            'status' => 'success',
            'message' => 'Review deleted'
        ]);
    }
}