gpablore/laravel-user-review
Add Google Play–style user reviews and star/point ratings to any Eloquent model via a simple trait. Users can leave one review with optional text; admins can post a single support reply. Includes migrations, config, and helpers for averages and percentages.
Install the Package
composer require dgvai/laravel-user-review
Publish Config & Migrations
php artisan vendor:publish --provider="DGvai\Review\ReviewerServiceProvider"
php artisan migrate
php artisan config:cache
Apply the Trait
Add Reviewable to your model (e.g., Product, Service):
use DGvai\Review\Traits\Reviewable;
class Product extends Model
{
use Reviewable;
}
First Review Submission
Use the submitReview() method in a controller:
$review = $product->submitReview([
'rating' => 5, // Required (1-5 stars)
'comment' => 'Great product!',
'user_id' => auth()->id(), // Auto-fetched if using middleware
]);
Review Submission
rating between 1–5, comment max length).public function store(Request $request, $model, $id)
{
$modelInstance = $model::findOrFail($id);
$review = $modelInstance->submitReview($request->all() + ['user_id' => auth()->id()]);
return redirect()->back()->with('success', 'Review submitted!');
}
Admin Replies
replyToReview():
$review->replyToReview(['response' => 'Thank you for your feedback!']);
hasAdminReply() to toggle reply visibility in Blade:
@if($review->hasAdminReply())
<div class="admin-reply">{{ $review->adminReply->response }}</div>
@endif
Displaying Reviews
$product->reviews → Collection of all reviews.$product->averageRating → Float (e.g., 4.2).$product->starRating() → HTML string (e.g., <div class="stars">★★★★☆</div>).<div class="reviews">
@foreach($product->reviews as $review)
<div class="review">
<div class="rating">{{ $review->starRating() }}</div>
<p>{{ $review->comment }}</p>
@include('partials.admin-reply', ['review' => $review])
</div>
@endforeach
</div>
API Integration
public function toArray($request)
{
return [
'id' => $this->id,
'rating' => $this->rating,
'comment' => $this->comment,
'admin_reply' => $this->adminReply?->response,
'created_at' => $this->created_at->diffForHumans(),
];
}
Missing Middleware
submitReview() expects auth()->id() to be set. Unauthenticated users will fail silently.Route::middleware(['auth'])->group(function () {
Route::post('/products/{product}/reviews', [ReviewController::class, 'store']);
});
Duplicate Reviews
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
], [
'user_id.unique' => 'You have already reviewed this item.',
]);
Admin Reply Overwrite
replyToReview() overwrites existing replies without warning.if ($review->adminReply) {
return back()->with('error', 'Reply already exists.');
}
Missing Database Tables
submitReview() fails with SQLSTATE[42S02].config/review.php for table names.Rating Calculation Errors
averageRating returns null or incorrect values.reviews relationship in your model:
public function reviews()
{
return $this->hasMany(Review::class);
}
Custom Review Model
Review model (e.g., add ip_address for fraud detection).getReviewModel() method:
class Product extends Model
{
use Reviewable;
protected function getReviewModel()
{
return \App\Models\CustomReview::class;
}
}
Dynamic Rating Scales
protected function getRatingRules()
{
return ['rating' => 'required|integer|min:1|max:10'];
}
Soft Deletes for Reviews
SoftDeletes to the Review model and update the trait’s delete() method:
use Illuminate\Database\Eloquent\SoftDeletes;
class Review extends Model
{
use SoftDeletes;
}
Localization
comment/response as JSON:
$review->comment = ['en' => 'Great!', 'es' => '¡Excelente!'];
How can I help you explore Laravel packages today?