Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rating Laravel Package

kosmoskosmos/rating

Laravel package for adding star ratings to Eloquent models. Supports polymorphic ratings, configurable scales, average score calculations, and simple helpers for displaying rating summaries in your app.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before installing. The package targets Laravel Nova and Laravel 9/10-era PHP (8.1/8.2). Check composer.json inside the package for illuminate/*, laravel/nova, and php constraints against your project. Nova 5 / PHP 8.3 compatibility is not guaranteed given the October 2023 last release.

composer require kosmoskosmos/rating

2. Publish and run the migration. The package ships a ratings table migration (polymorphic: rateable_type, rateable_id, user_id, rating/score). Publish via the service provider:

php artisan vendor:publish --provider="Kosmos\Rating\RatingServiceProvider"
php artisan migrate

Verify the actual provider FQCN first with php artisan vendor:publish (interactive list) or by reading vendor/kosmoskosmos/rating/src. The Composer name (kosmoskosmos/rating) and repo name (nova-rating) differ, so don't assume the namespace from either.

3. Add the trait to your rateable model.

use Kosmos\Rating\Traits\Rateable; // confirm namespace

class Product extends Model
{
    use Rateable;
}

4. Register the Nova field on the resource.

use Kosmos\Rating\Rating; // confirm namespace

public function fields(NovaRequest $request)
{
    return [
        Rating::make('Rating'),
    ];
}

Where to look first: vendor/kosmoskosmos/rating/src/ — the trait (defines rate(), ratings(), aggregate helpers), the Nova field class (defines index/detail/form behavior), and config/rating.php if present (table name, user model, storage column).

First real use case: per-user star ratings on a Product. A logged-in user submits 1–5 stars in the Nova detail form or via your own endpoint; the model exposes an average for index columns and API responses. With 3 stars and 0 dependents, scope your first integration to a single low-risk resource and validate the output before spreading it.

Implementation Patterns

Write path — rate once, update thereafter. Duplicate ratings are the most common failure mode. Wrap writes so a user can only ever hold one rating per rateable:

$product->ratings()->updateOrCreate(
    ['user_id' => auth()->id()],
    ['rating' => $request->integer('rating')]
);

Or use the trait's own method if it provides one ($product->rate($value) / $product->rate($value, $user)) — read the trait source to see whether it uses updateOrCreate internally or blindly create()s. If it creates, add a unique DB index and handle the collision.

Read path — never call averageRating() in a loop. On a Nova index with 50 rows that is 50 aggregate queries. Use constrained eager loading with aliases and point the field at the alias:

public function indexQuery(NovaRequest $request, $query)
{
    return $query
        ->withAvg('ratings', 'rating')
        ->withCount('ratings');
}
Rating::make('Avg Rating', 'ratings_avg_rating')
    ->sortable(),          // only if it maps to a real/aliased column
Rating::make('Votes', 'ratings_count')->sortable(),

Sorting by rating. orderBy('ratings_avg_rating') works against the withAvg alias in MySQL/Postgres; make the Nova field sortable() and confirm the generated ORDER BY references the alias, not a nonexistent rating column.

Form vs. display. Typical split: a writable Rating::make('Rating') on the update/create forms, and read-only computed fields (ratings_avg_rating, ratings_count) on index/detail. If the field renders stars on index, confirm it degrades gracefully at null (no ratings yet) rather than showing zero stars as a real score.

API / non-Nova consumption. The trait is the real product; the Nova field is a thin view. Expose ratings through a controller and a RatingResource so mobile/JS clients use the same write path as Nova. Return avg rounded at the presentation layer, not in the DB.

Caching aggregates. Averages are read far more than written. Cache avg and count per rateable with a short TTL or bust them in a model observer on the Rating model (saved/deleted). This is the cheapest way to make the package viable on listing pages.

Composition with other fields. Because the storage is polymorphic, the same ratings table can serve Product, Post, and User without schema changes. Adopt Relation::morphMap() early so rateable_type stores stable aliases ('product') instead of FQCNs.

Gotchas and Tips

  • Unmaintained since Oct 2023 with 3 stars / 0 dependents. Treat it as a small internal utility, not infrastructure. There is no community to catch bugs and no upgrade path. Read all ~few hundred lines of src/ before adopting; you can realistically fork or copy it into app/ and own it.
  • Namespace guessing is the #1 install friction. Package name, repo name, and PHP namespace are all plausible mismatches. Always discover with php artisan vendor:publish and grep -r "namespace" vendor/kosmoskosmos/rating/src before writing imports.
  • (rateable_type, rateable_id, user_id) needs a unique index. The bundled migration may not include it. Add it in a follow-up migration; without it, races and double-clicks silently produce two ratings and skewed averages.
  • Morph map drift. Default polymorphic storage writes full class names. If you later move or rename a model, historical ratings orphan silently. Register Relation::morphMap() before the first row is written, not after.
  • Integer vs. decimal storage. If the column is tinyint, per-user values are integers and your average is a float — round only at render time. If the column is decimal, make sure the field's rules() constrain input to your scale, otherwise Nova accepts 4.75 into a decimal(3,1) and truncation surprises you.
  • Null vs. zero ratings. An unrated model returns null from withAvg, which often renders as 0 stars and reads as "rated 0". Use displayUsing() to render "—" or "No ratings" for null.
  • Guest/anonymous ratings. If you allow user_id = null, the unique index still allows unlimited NULL rows in MySQL — duplicates are permitted. Either enforce auth or add a session-key column.
  • Eager-load or drown. The dominant production issue with this class of package is averageRating() in a Blade/Nova loop. Audit every call site with DB::listen() (or Telescope) in a staging index request before shipping.
  • Extension points are thin. Expect a publishable config for table/model names at most. If you need per-criterion ratings, weighted scores, or review text, this package is a starting point — subclass the Rating model and point the config at it, or fork outright.
  • Debugging queries. Confirm the trait's relation name (ratings()) matches what the field and your aggregates reference; a renamed relation silently returns null averages rather than erroring.
  • Pin the version. "kosmoskosmos/rating": "1.0.*" (or whatever the exact tag is) in composer.json rather than a floating constraint. With no maintainer activity, an unpinned composer update cannot be relied upon to be a no-op.
  • Nova upgrade risk. Nova 5 changed field APIs. Before any Nova major upgrade, write a throwaway test that instantiates the field on a resource and resolves it, so a breakage surfaces in CI rather than in the admin panel.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc