jobmetric/laravel-star
jobmetric/laravel-star adds a flexible star-rating system to Laravel apps. Attach ratings to Eloquent models, store user votes, calculate averages, and render star displays in Blade with configurable options for reviews and scoring.
The 2.0 release turns this from a bare rating model into a configurable package: config file, translations (including fa), events, exceptions, a factory, and two traits (HasStar for the model being rated, CanStar for the model doing the rating). Start by reading those four things in this order:
config/star.php) — it defines the table name, model bindings, and probably the rating constraints. This is the file you will touch most.CanStar — the write API (who gives the star).HasStar — the read/relationship API (who receives stars).Install and publish:
composer require vendor/package
# List the provider's publish groups, then publish config + migrations + lang
php artisan vendor:publish
php artisan migrate
Wire the traits:
use Vendor\Package\Traits\HasStar;
class Post extends Model
{
use HasStar; // Post can be starred
}
class User extends Authenticatable
{
use CanStar; // User can give stars
}
First use case — rate a post from a controller:
public function store(Post $post, RatePostRequest $request)
{
$request->user()->star($post, $request->integer('star'));
// exact method signature lives in CanStar; check its docblock
return back();
}
Reading back is done through HasStar. If the aggregate accessors are not obvious from the trait, drop to the relationship:
$post->stars()->avg('star');
$post->stars()->count();
Config-first model wiring. Because 2.0 introduces a config file, resolve the Star model, table name, and user model from config rather than hardcoding. Bind a custom Star subclass in config if you need extra columns; the factory and relationships should follow the configured model.
Trait placement is the contract. Put HasStar on the rateable model and CanStar on the actor (usually User). Do not put both on the same model unless you genuinely have self-rating — it makes queries ambiguous and complicates authorization policies.
Use the events, not model observers. 2.0 ships event classes. Register listeners for created/updated/deleted stars to invalidate cached averages, notify the post author, or write an activity log. This is cleaner than observing the Star model directly and survives a model swap via config.
// EventServiceProvider (or bootstrap/app.php on Laravel 11)
Event::listen(StarCreated::class, RecalculatePostRating::class);
Event::listen(StarCreated::class, NotifyPostAuthor::class);
Translate exceptions in the request layer. 2.0 adds exception classes (duplicate star, invalid value, etc.). Catch them in a FormRequest or a small action class and return a 422 with the translated message rather than letting them bubble to a 500:
try {
$user->star($post, $request->integer('star'));
} catch (AlreadyStarredException $e) {
throw ValidationException::withMessages([
'star' => __('star::messages.already_starred'),
]);
}
Localization. The package now ships en and fa files. Publish the lang group and override keys under lang/{locale}/star.php or the vendor namespace; fall back to config('app.fallback_locale') for locales you have not translated. If you support fa, remember that locale switching affects exception messages returned to the client.
Factory-driven tests. Use the new factory instead of hand-building stars. This keeps tests aligned with the changed migration schema:
$post = Post::factory()->create();
$user = User::factory()->create();
Star::factory()->for($post)->for($user)->create(['star' => 4]);
$this->assertSame(4.0, (float) $post->stars()->avg('star'));
Aggregates and list screens. For index pages, avoid N+1 by using withAvg/withCount on the star relationship where possible, or cache the average and invalidate from the StarCreated/StarDeleted listeners. Show a "your rating" state by eager-loading the current user's star.
Authorization. Enforce "one rating per user per model" in a policy or FormRequest rule before calling CanStar. The package's duplicate exception is a safety net, not the primary UX.
HasStar, the Star model, the factory, and the migration table all changed. If you are upgrading, do not just composer update: diff the published migration against yours, re-publish the config and lang files, and check every call site against the new trait signatures. Existing rows may need a data migration.php artisan config:clear and php artisan optimize:clear — a cached config from 1.x will silently point at the old model/table.Relation::enforceMorphMap(), the starable_type values depend on your map, not class names. Changing the map later orphans existing stars; write a data migration if you rename an alias.between:1,5.ShouldQueue — otherwise a rating request blocks on mail/HTTP. Also ensure listeners are registered in the right place for your Laravel version (EventServiceProvider vs bootstrap/app.php).fa. If you have not published translations, exception messages may come back in the fallback locale. Test with App::setLocale('fa') in a feature test.Star model, custom table, custom user resolver. Prefer subclassing the model plus config binding over forking the package. Exceptions and events are the other two seams — listen for events and map exceptions to your API's error format.CanStar API everywhere else so events and exceptions fire consistently.How can I help you explore Laravel packages today?