PHPackages                             andydefer/laravel-ratings - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. andydefer/laravel-ratings

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

andydefer/laravel-ratings
=========================

Polymorphic rating and review system for Laravel with star ratings (1-5), reviews, average calculations, and distribution statistics.

v1.0.0(yesterday)00MITPHPPHP ^8.2

Since Jun 20Pushed yesterdayCompare

[ Source](https://github.com/andydefer/laravel-ratings)[ Packagist](https://packagist.org/packages/andydefer/laravel-ratings)[ RSS](/packages/andydefer-laravel-ratings/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (11)Versions (2)Used By (0)

Laravel Ratings
===============

[](#laravel-ratings)

> Système d'évaluation et d'avis polymorphique pour applications Laravel

Un package Laravel complet pour gérer des évaluations par étoiles (1 à 5) avec avis textuels, calculs de moyenne, distribution des notes et support polymorphique.

---

📋 Table des matières
--------------------

[](#-table-des-matières)

- [Fonctionnalités](#fonctionnalit%C3%A9s)
- [Prérequis](#pr%C3%A9requis)
- [Installation](#installation)
- [Configuration](#configuration)
- [Utilisation](#utilisation)
    - [Créer une évaluation](#cr%C3%A9er-une-%C3%A9valuation)
    - [Modifier une évaluation](#modifier-une-%C3%A9valuation)
    - [Supprimer une évaluation](#supprimer-une-%C3%A9valuation)
    - [Vérifier une évaluation](#v%C3%A9rifier-une-%C3%A9valuation)
    - [Récupérer les évaluations](#r%C3%A9cup%C3%A9rer-les-%C3%A9valuations)
    - [Statistiques et moyennes](#statistiques-et-moyennes)
    - [Filtrer par niveau](#filtrer-par-niveau)
- [Niveaux d'évaluation](#niveaux-d%C3%A9valuation)
- [Référence de l'API](#r%C3%A9f%C3%A9rence-de-lapi)
- [Value Objects](#value-objects)
- [Structure de la base de données](#structure-de-la-base-de-donn%C3%A9es)
- [Tests](#tests)
- [Contribuer](#contribuer)
- [Licence](#licence)

---

✨ Fonctionnalités
-----------------

[](#-fonctionnalités)

- ✅ **Double polymorphisme** - Évaluez n'importe quel modèle avec n'importe quel utilisateur
- ✅ **5 niveaux d'évaluation** - ⭐ à ⭐⭐⭐⭐⭐ avec labels personnalisés
- ✅ **Avis textuels** - Commentaires optionnels associés aux notes
- ✅ **Calcul de moyenne** - Note moyenne automatique avec arrondi à 2 décimales
- ✅ **Distribution des notes** - Répartition des évaluations par niveau
- ✅ **Anti-doublon** - Un utilisateur ne peut pas évaluer deux fois le même objet
- ✅ **Pattern Repository** - Séparation propre de la logique d'accès aux données
- ✅ **Support des DTOs** - Objets de transfert de données typés
- ✅ **Value Objects** - DateTime, Métadonnées
- ✅ **Support des métadonnées** - Stockez des données supplémentaires au format JSON
- ✅ **Suppression douce** - Suppression sécurisée avec possibilité de restauration
- ✅ **Filtrage avancé** - Filtrez par note minimale, maximale, par auteur, par objet

---

🚀 Prérequis
-----------

[](#-prérequis)

- PHP 8.2 ou supérieur
- Laravel 12.0, 13.0, 14.0 ou 15.0

---

📦 Installation
--------------

[](#-installation)

Installez le package via Composer :

```
composer require andydefer/laravel-ratings
```

### Publier les migrations

[](#publier-les-migrations)

```
php artisan vendor:publish --tag=Ratings-migrations
```

### Exécuter les migrations

[](#exécuter-les-migrations)

```
php artisan migrate
```

---

⚙️ Configuration
----------------

[](#️-configuration)

Le package est automatiquement découvert par Laravel. Aucune configuration supplémentaire n'est requise.

Si vous devez personnaliser le Service Provider, ajoutez-le manuellement dans `config/app.php` :

```
'providers' => [
    // ...
    AndyDefer\LaravelRatings\RatingsServiceProvider::class,
],
```

---

📖 Utilisation
-------------

[](#-utilisation)

### Créer une évaluation

[](#créer-une-évaluation)

```
use AndyDefer\LaravelRatings\Services\RatingService;
use AndyDefer\LaravelRatings\Enums\RatingLevel;

class ProductController extends Controller
{
    public function rate(RatingService $ratingService, Product $product)
    {
        $user = auth()->user();

        // Évaluer avec 5 étoiles et un avis
        $rating = $ratingService->rate(
            rater: $user,
            rateable: $product,
            rating: RatingLevel::FIVE,
            review: 'Excellent produit, je recommande vivement !'
        );

        return response()->json([
            'message' => 'Évaluation ajoutée avec succès',
            'rating' => $rating
        ]);
    }
}
```

### Modifier une évaluation

[](#modifier-une-évaluation)

```
public function updateRating(RatingService $ratingService, Product $product)
{
    $user = auth()->user();

    try {
        $updated = $ratingService->updateRating(
            rater: $user,
            rateable: $product,
            rating: RatingLevel::FOUR,
            review: 'Très bon produit, mais quelques petites améliorations possibles'
        );

        return response()->json([
            'message' => 'Évaluation mise à jour',
            'rating' => $updated
        ]);
    } catch (RuntimeException $e) {
        return response()->json(['error' => $e->getMessage()], 404);
    }
}
```

### Supprimer une évaluation

[](#supprimer-une-évaluation)

```
public function deleteRating(RatingService $ratingService, Product $product)
{
    $user = auth()->user();

    try {
        $ratingService->deleteRating($user, $product);

        return response()->json([
            'message' => 'Évaluation supprimée avec succès'
        ]);
    } catch (RuntimeException $e) {
        return response()->json(['error' => $e->getMessage()], 404);
    }
}
```

### Vérifier une évaluation

[](#vérifier-une-évaluation)

```
// Vérifier si l'utilisateur a déjà évalué
$hasRated = $ratingService->hasRated($user, $product);

// Récupérer l'évaluation spécifique
$rating = $ratingService->getRaterRating($user, $product);
```

### Récupérer les évaluations

[](#récupérer-les-évaluations)

```
// Récupérer toutes les évaluations d'un produit
$ratings = $ratingService->getRatings($product);

// Récupérer toutes les évaluations d'un utilisateur
$userRatings = $ratingService->getRatingsByRater($user);

// Récupérer uniquement les bonnes notes (4⭐ et 5⭐)
$topRatings = $ratingService->getRatings(
    rateable: $product,
    minRating: RatingLevel::FOUR
);
```

### Statistiques et moyennes

[](#statistiques-et-moyennes)

```
// Calculer la note moyenne
$average = $ratingService->getAverageRating($product); // 4.2

// Compter le nombre total d'évaluations
$total = $ratingService->countRatings($product); // 127

// Compter les évaluations par niveau
$fiveStars = $ratingService->countRatingsByLevel($product, RatingLevel::FIVE);

// Obtenir la distribution complète
$distribution = $ratingService->getRatingDistribution($product);
// [
//     1 => 2,
//     2 => 5,
//     3 => 10,
//     4 => 32,
//     5 => 78
// ]
```

### Filtrer par niveau

[](#filtrer-par-niveau)

```
// Récupérer les évaluations entre 3⭐ et 5⭐
$filtered = $ratingService->getRatings(
    rateable: $product,
    minRating: RatingLevel::THREE,
    maxRating: RatingLevel::FIVE
);

// Récupérer uniquement les notes supérieures à 3⭐
$goodRatings = $ratingService->getRatings(
    rateable: $product,
    minRating: RatingLevel::FOUR
);

// Récupérer uniquement les notes inférieures à 3⭐
$badRatings = $ratingService->getRatings(
    rateable: $product,
    maxRating: RatingLevel::THREE
);
```

---

🏷️ Niveaux d'évaluation
-----------------------

[](#️-niveaux-dévaluation)

NiveauValeurÉtoilesLabel`RatingLevel::ONE``1`⭐Très mauvais`RatingLevel::TWO``2`⭐⭐Mauvais`RatingLevel::THREE``3`⭐⭐⭐Moyen`RatingLevel::FOUR``4`⭐⭐⭐⭐Bien`RatingLevel::FIVE``5`⭐⭐⭐⭐⭐Excellent### Utilisation des étoiles et labels

[](#utilisation-des-étoiles-et-labels)

```
use AndyDefer\LaravelRatings\Enums\RatingLevel;

$level = RatingLevel::FIVE;
echo $level->getStars();       // ⭐⭐⭐⭐⭐
echo $level->getLabel();       // Excellent
echo $level->getPercentage();  // 100%

$level = RatingLevel::THREE;
echo $level->getStars();       // ⭐⭐⭐
echo $level->getLabel();       // Moyen
echo $level->getPercentage();  // 60%
```

---

📚 Référence de l'API
--------------------

[](#-référence-de-lapi)

### RatingService

[](#ratingservice)

MéthodeDescriptionRetourne`rate(Model $rater, Model $rateable, RatingLevel $rating, ?string $review)`Crée une évaluation`Model``updateRating(Model $rater, Model $rateable, RatingLevel $rating, ?string $review)`Modifie une évaluation`Model``deleteRating(Model $rater, Model $rateable)`Supprime une évaluation`void``hasRated(Model $rater, Model $rateable)`Vérifie si une évaluation existe`bool``getRaterRating(Model $rater, Model $rateable)`Récupère l'évaluation d'un utilisateur`?Model``getRatings(Model $rateable, ?RatingLevel $minRating, ?RatingLevel $maxRating)`Récupère les évaluations d'un objet`Collection``getRatingsByRater(Model $rater)`Récupère les évaluations d'un utilisateur`Collection``getAverageRating(Model $rateable)`Calcule la note moyenne`float``getRatingDistribution(Model $rateable)`Obtient la distribution des notes`array``countRatings(Model $rateable)`Compte les évaluations`int``countRatingsByLevel(Model $rateable, RatingLevel $level)`Compte les évaluations par niveau`int`### RatingRepository

[](#ratingrepository)

MéthodeDescriptionRetourne`getAverageRating(Model $rateable)`Calcule la note moyenne`float``getRatingDistribution(Model $rateable)`Obtient la distribution des notes`array`---

🎯 Value Objects
---------------

[](#-value-objects)

Le package supporte les Value Objects suivants :

Value ObjectDescriptionExemple`DateTimeVO`Date/heure`DateTimeVO::from('2024-01-01 12:00:00')``StrictDataObject`Métadonnées typées`StrictDataObject::from(['key' => 'value'])`### Accesseurs dans le modèle Rating

[](#accesseurs-dans-le-modèle-rating)

```
$rating = Rating::find(1);

// Accès via les getters
$createdAt = $rating->getCreatedAt();    // DateTimeVO|null
$updatedAt = $rating->getUpdatedAt();    // DateTimeVO|null
$deletedAt = $rating->getDeletedAt();    // DateTimeVO|null
$metadata = $rating->getMetadata();      // StrictDataObject|null
$level = $rating->getRatingLevel();      // RatingLevel
$review = $rating->getReview();          // string|null

// Relations
$rater = $rating->rater;          // Auteur (User, Admin, etc.)
$rateable = $rating->rateable;    // Objet évalué (Product, Service, etc.)
```

---

📝 Structure de la base de données
---------------------------------

[](#-structure-de-la-base-de-données)

```
CREATE TABLE ratings (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    rater_type VARCHAR(255) NOT NULL,      -- Type de l'évaluateur
    rater_id BIGINT UNSIGNED NOT NULL,     -- ID de l'évaluateur
    rateable_type VARCHAR(255) NOT NULL,   -- Type de l'objet évalué
    rateable_id BIGINT UNSIGNED NOT NULL,  -- ID de l'objet évalué
    rating_level TINYINT NOT NULL,         -- 1, 2, 3, 4, 5
    review TEXT NULL,                      -- Avis textuel
    metadata JSON NULL,                    -- Métadonnées
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    deleted_at TIMESTAMP NULL,

    UNIQUE INDEX idx_unique_rating (rater_type, rater_id, rateable_type, rateable_id),
    INDEX idx_rater (rater_type, rater_id),
    INDEX idx_rateable (rateable_type, rateable_id),
    INDEX idx_rating_level (rating_level)
);
```

---

🔍 Exemple complet
-----------------

[](#-exemple-complet)

```
use AndyDefer\LaravelRatings\Services\RatingService;
use AndyDefer\LaravelRatings\Enums\RatingLevel;
use Illuminate\Http\Request;

class ProductReviewController extends Controller
{
    public function __construct(
        private readonly RatingService $ratingService
    ) {}

    public function store(Request $request, Product $product)
    {
        $user = $request->user();

        // Vérifier si l'utilisateur a déjà acheté le produit
        if (!$user->hasPurchased($product)) {
            return response()->json([
                'error' => 'Vous devez acheter le produit pour donner un avis'
            ], 403);
        }

        // Vérifier si l'utilisateur a déjà donné un avis
        if ($this->ratingService->hasRated($user, $product)) {
            return response()->json([
                'error' => 'Vous avez déjà donné votre avis sur ce produit'
            ], 422);
        }

        try {
            $rating = $this->ratingService->rate(
                rater: $user,
                rateable: $product,
                rating: RatingLevel::from($request->input('rating')),
                review: $request->input('review')
            );

            return response()->json([
                'message' => 'Avis publié avec succès',
                'rating' => $rating,
                'average' => $this->ratingService->getAverageRating($product),
                'total' => $this->ratingService->countRatings($product)
            ], 201);

        } catch (RuntimeException $e) {
            return response()->json([
                'error' => $e->getMessage()
            ], 422);
        }
    }

    public function show(Product $product)
    {
        $distribution = $this->ratingService->getRatingDistribution($product);
        $total = $this->ratingService->countRatings($product);
        $average = $this->ratingService->getAverageRating($product);
        $ratings = $this->ratingService->getRatings($product);

        return response()->json([
            'average_rating' => $average,
            'total_reviews' => $total,
            'distribution' => $distribution,
            'reviews' => $ratings->map(function ($rating) {
                return [
                    'id' => $rating->id,
                    'user' => $rating->rater->name,
                    'rating' => $rating->getRatingLevel()->value,
                    'stars' => $rating->getRatingLevel()->getStars(),
                    'review' => $rating->getReview(),
                    'created_at' => $rating->getCreatedAt()?->format('Y-m-d H:i:s')
                ];
            })
        ]);
    }

    public function update(Request $request, Product $product)
    {
        $user = $request->user();

        try {
            $updated = $this->ratingService->updateRating(
                rater: $user,
                rateable: $product,
                rating: RatingLevel::from($request->input('rating')),
                review: $request->input('review')
            );

            return response()->json([
                'message' => 'Avis mis à jour',
                'rating' => $updated
            ]);

        } catch (RuntimeException $e) {
            return response()->json([
                'error' => $e->getMessage()
            ], 404);
        }
    }

    public function destroy(Product $product)
    {
        $user = request()->user();

        try {
            $this->ratingService->deleteRating($user, $product);

            return response()->json([
                'message' => 'Avis supprimé avec succès'
            ]);

        } catch (RuntimeException $e) {
            return response()->json([
                'error' => $e->getMessage()
            ], 404);
        }
    }

    public function myReviews(Request $request)
    {
        $user = $request->user();
        $ratings = $this->ratingService->getRatingsByRater($user);

        return response()->json([
            'total' => $ratings->count(),
            'reviews' => $ratings
        ]);
    }

    public function stats(Product $product)
    {
        $distribution = $this->ratingService->getRatingDistribution($product);
        $total = $this->ratingService->countRatings($product);
        $average = $this->ratingService->getAverageRating($product);

        // Préparer les données pour l'affichage
        $formattedDistribution = [];
        foreach (RatingLevel::cases() as $level) {
            $formattedDistribution[$level->value] = [
                'label' => $level->getLabel(),
                'stars' => $level->getStars(),
                'count' => $distribution[$level->value] ?? 0,
                'percentage' => $total > 0
                    ? round(($distribution[$level->value] ?? 0) / $total * 100, 1)
                    : 0
            ];
        }

        return response()->json([
            'product' => $product->name,
            'average_rating' => $average,
            'total_reviews' => $total,
            'distribution' => $formattedDistribution
        ]);
    }
}
```

---

🧪 Tests
-------

[](#-tests)

### Exécuter les tests

[](#exécuter-les-tests)

```
composer test
```

### Exécuter uniquement les tests unitaires

[](#exécuter-uniquement-les-tests-unitaires)

```
composer test-unit
```

### Exécuter uniquement les tests d'intégration

[](#exécuter-uniquement-les-tests-dintégration)

```
composer test-integration
```

### Configuration des tests

[](#configuration-des-tests)

Le package utilise `orchestra/testbench` pour les tests d'intégration avec une base de données SQLite en mémoire.

---

🔧 Développement
---------------

[](#-développement)

### Style de code

[](#style-de-code)

```
./vendor/bin/pint
```

### Analyse statique

[](#analyse-statique)

```
./vendor/bin/phpstan analyse
./vendor/bin/psalm
```

---

🤝 Contribuer
------------

[](#-contribuer)

Veuillez consulter [CONTRIBUTING](CONTRIBUTING.md) pour plus de détails.

### Flux de développement

[](#flux-de-développement)

1. Forkez le dépôt
2. Créez une branche de fonctionnalité (`git checkout -b feature/amazing-feature`)
3. Apportez vos modifications
4. Exécutez les tests (`composer test`)
5. Committez vos modifications (`git commit -m 'Ajouter une fonctionnalité géniale'`)
6. Poussez vers la branche (`git push origin feature/amazing-feature`)
7. Ouvrez une Pull Request

---

📦 Dépendances
-------------

[](#-dépendances)

- [`andydefer/php-vo`](https://github.com/andydefer/php-vo) - Value Objects
- [`andydefer/laravel-repository`](https://github.com/andydefer/laravel-repository) - Implémentation du pattern Repository
- [`andydefer/domain-structures`](https://github.com/andydefer/domain-structures) - Structures de domaine (AbstractRecord, AbstractData)

---

👨‍💻 Auteur
----------

[](#‍-auteur)

**Andy Kani**

- GitHub: [@andydefer](https://github.com/andydefer)
- Email:

---

📄 Licence
---------

[](#-licence)

Ce package est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus d'informations.

---

⭐ Support
---------

[](#-support)

Si vous trouvez ce package utile, n'hésitez pas à lui donner une ⭐ sur GitHub !

---

🙏 Remerciements
---------------

[](#-remerciements)

- Framework Laravel
- Tous les contributeurs et utilisateurs de ce package

---

**Construit avec ❤️ pour la communauté Laravel**

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2170ec3fbad9eb4b002661ab4f58b1cc374eae4293b92904c6a74bc2818bd570?d=identicon)[andydefer](/maintainers/andydefer)

---

Top Contributors

[![andydefer](https://avatars.githubusercontent.com/u/124321745?v=4)](https://github.com/andydefer "andydefer (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/andydefer-laravel-ratings/health.svg)

```
[![Health](https://phpackages.com/badges/andydefer-laravel-ratings/health.svg)](https://phpackages.com/packages/andydefer-laravel-ratings)
```

###  Alternatives

[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17818.7k](/packages/markwalet-nova-modal-response)[crumbls/layup

A visual page builder plugin for Filament 5 — Divi-style grid layouts with extensible widgets.

591.7k1](/packages/crumbls-layup)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

119.2k](/packages/tomshaw-electricgrid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
