beksos/reviewmaster
Laravel package to add user reviews and star/point ratings to any Eloquent model via a Reviewable trait. Supports configurable user model and a single admin reply per review (Google Play-style). Includes migrations, config publishing, and helper methods like makeReview().
Installation
composer require beksos/reviewmaster
Publish the migration and config:
php artisan vendor:publish --provider="BechirAhmed\Reviewmaster\ReviewmasterServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="BechirAhmed\Reviewmaster\ReviewmasterServiceProvider" --tag="config"
Run the migration:
php artisan migrate
Configure Models
Add HasReviews trait to your model (e.g., Product):
use BechirAhmed\Reviewmaster\Traits\HasReviews;
class Product extends Model
{
use HasReviews;
}
First Review Create a review for a product:
$product = Product::find(1);
$review = $product->reviews()->create([
'user_id' => auth()->id(),
'rating' => 5,
'comment' => 'Great product!',
]);
Display Reviews Fetch and display reviews for a product:
$reviews = Product::find(1)->reviews()->with('user')->get();
Review Creation
createReview() helper method on models:
$product->createReview($request->all());
ReviewRequest (if provided in the package).Aggregating Ratings
$avgRating = $product->averageRating;
$reviewCount = $product->reviewCount;
Filtering & Sorting
$highRated = $product->reviews()->where('rating', '>=', 4)->get();
$recentReviews = $product->reviews()->latest()->get();
User-Specific Logic
$product->hasReviewFrom(auth()->id());
$this->validate($request, [
'rating' => 'required|integer|min:1|max:5',
// ...
]);
API Responses
return Product::with(['reviews.user'])->find($id);
ReviewResource) if provided.Blade Views Loop through reviews in a template:
@foreach($product->reviews as $review)
<div class="review">
<p>Rating: {{ $review->rating }}/5</p>
<p>{{ $review->comment }}</p>
<small>By {{ $review->user->name }}</small>
</div>
@endforeach
Admin Panels
$reviews = Review::query()
->whereHas('reviewable', function ($q) {
$q->where('type', Product::class);
})->get();
Notifications
event(new ReviewCreated($review));
Caching
averageRating) to reduce DB load:
Cache::remember("product_{$product->id}_rating", now()->addHours(1), function () use ($product) {
return $product->averageRating;
});
Testing
$product = Product::factory()->create();
$product->createReview(['rating' => 5, 'comment' => 'Test']);
$this->assertEquals(5, $product->fresh()->averageRating);
Missing Foreign Key
reviewable_id and reviewable_type columns exist in the reviews table. If not, re-run migrations or manually add them:
Schema::table('reviews', function (Blueprint $table) {
$table->unsignedBigInteger('reviewable_id');
$table->string('reviewable_type');
});
Polymorphic Relationships
public function reviews()
{
return $this->morphMany(Review::class, 'reviewable');
}
User Association
user_id field is assumed to exist in the reviews table. If not, add it to the migration or config.Rating Validation
ReviewRequest or add custom validation:
$this->validate($request, ['rating' => 'required|integer|between:1,5']);
Soft Deletes
reviews table also has a deleted_at column and the relationship accounts for it:
return $this->morphMany(Review::class, 'reviewable')->withTrashed();
Query Logs
DB::enableQueryLog();
$product->reviews; // Trigger the relationship
dd(DB::getQueryLog());
Common Errors
reviewable_type matches your model’s class name (e.g., App\Models\Product).reviews table columns match the migration (e.g., rating, comment, user_id).Seeding
$product = Product::factory()->create();
Review::factory()->count(5)->create(['reviewable_id' => $product->id, 'reviewable_type' => Product::class]);
Custom Review Models
Review model to add fields (e.g., helpful_votes):
class Review extends \BechirAhmed\Reviewmaster\Models\Review
{
protected $fillable = ['helpful_votes', ...];
}
Custom Validation
public function rules()
{
return [
'rating' => 'required|integer|min:1|max:5|not_in:0',
'comment' => 'required|string|max:1000',
];
}
Custom Aggregations
public function getPositiveRatingPercentageAttribute()
{
return $this->reviews()->where('rating', '>=', 4)->count() / $this->reviewCount * 100;
}
Events
ReviewCreated::subscribe(function ($review) {
// Send email, update analytics, etc.
});
API Resources
ReviewResource to hide sensitive data:
public function toArray($request)
{
return [
'id' => $this->id,
'rating' => $this->rating,
'comment' => Str::limit($this->comment, 100),
'user' => UserResource::make($this->whenLoaded('user')),
];
}
Reviewable Models
config/reviewmaster.php may define allowed reviewable models. Ensure your model is listed:
'models' => [
'product' => \App\Models\Product::class,
],
Default Values
'max_rating' => 5,
'min_rating' => 1,
Guard Clauses
How can I help you explore Laravel packages today?