andydefer / laravel-mixins
A collection of reusable Laravel model traits for availability, ratings, and more
Requires
- php: ^8.1
- andydefer/laravel-chronos: ^0.7.16
- andydefer/laravel-ratings: ^1.3.10
- laravel/framework: ^12.0|^13.0|^14.0|^15.0
Requires (Dev)
- laravel/pint: ^1.29
- mockery/mockery: ^1.6
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^10.5|^11.0|^12.0
README
Collection de traits Eloquent réutilisables pour Laravel
Un package Laravel qui fournit des traits pour ajouter rapidement des attributs de disponibilité et d'évaluation à vos modèles Eloquent.
📋 Table des matières
- Fonctionnalités
- Prérequis
- Installation
- Configuration
- Utilisation
- Référence de l'API
- Exemples complets
- Tests
- Contribuer
- Licence
✨ Fonctionnalités
- ✅ HasAvailabilityAttributes - Attributs de disponibilité pour les modèles planifiables
- ✅ HasRatingAttributes - Attributs d'évaluation pour les modèles notables
- ✅ Attributs Eloquent typés - Accès direct aux propriétés du modèle
- ✅ Value Objects - Retourne des objets typés (SlotVO, DateTimeZuluVO)
- ✅ Intégration native - Fonctionne avec Laravel Chronos et Laravel Ratings
- ✅ Personnalisable - Surchargez
isSchedulable()etisRateable()pour des conditions métier - ✅ 0 configuration - Fonctionne immédiatement après installation
🚀 Prérequis
- PHP 8.1 ou supérieur
- Laravel 12.0, 13.0, 14.0 ou 15.0
andydefer/laravel-chronos^1.0andydefer/laravel-ratings^1.0
📦 Installation
Installez le package via Composer :
composer require andydefer/laravel-mixins
Publier la configuration (optionnel)
php artisan vendor:publish --tag=mixins-config
⚙️ 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\Mixins\MixinsServiceProvider::class, ],
Fichier de configuration
// config/mixins.php return [ 'slot_duration' => env('MIXINS_SLOT_DURATION', 30), 'min_slot_duration' => env('MIXINS_MIN_SLOT_DURATION', 15), ];
📖 Utilisation
HasAvailabilityAttributes
Ajoutez le trait à votre modèle pour bénéficier des attributs de disponibilité.
use AndyDefer\Mixins\Traits\HasAvailabilityAttributes; use Illuminate\Database\Eloquent\Model; final class Doctor extends Model { use HasAvailabilityAttributes; // Surchargez cette méthode pour ajouter des conditions personnalisées protected function isSchedulable(): bool { return $this->is_active && $this->user_type->isDoctor(); } }
Attributs disponibles
| Attribut | Type | Description |
|---|---|---|
$model->is_available_now |
bool |
L'entité est-elle disponible maintenant ? |
$model->next_slot |
SlotVO|null |
Prochain créneau disponible |
$model->has_availability_on_date |
bool |
L'entité a-t-elle des disponibilités aujourd'hui ? |
$model->total_available_minutes |
int |
Total des minutes disponibles aujourd'hui |
$doctor = Doctor::find(1); // Vérifier la disponibilité immédiate if ($doctor->is_available_now) { echo "Le médecin est disponible maintenant"; } // Récupérer le prochain créneau $nextSlot = $doctor->next_slot; if ($nextSlot) { $start = $nextSlot->getStart()->toDateTimeString(); $end = $nextSlot->getEnd()->toDateTimeString(); echo "Prochain créneau : $start - $end"; } // Vérifier les disponibilités du jour if ($doctor->has_availability_on_date) { $minutes = $doctor->total_available_minutes; echo "Disponible aujourd'hui : $minutes minutes"; }
HasRatingAttributes
Ajoutez le trait à votre modèle pour bénéficier des attributs d'évaluation.
use AndyDefer\Mixins\Traits\HasRatingAttributes; use Illuminate\Database\Eloquent\Model; final class Product extends Model { use HasRatingAttributes; // Surchargez cette méthode pour ajouter des conditions personnalisées protected function isRateable(): bool { return $this->is_active && $this->status === 'published'; } }
Attributs disponibles
| Attribut | Type | Description |
|---|---|---|
$model->average_rating |
float |
Note moyenne (0.0 si aucune note) |
$model->rating_count |
int |
Nombre total d'évaluations |
$model->rating_distribution |
array |
Distribution des notes par niveau (1-5) |
$model->has_ratings |
bool |
Le modèle a-t-il des évaluations ? |
$product = Product::find(1); // Afficher la note moyenne echo "Note moyenne : {$product->average_rating} / 5"; // Afficher le nombre d'avis echo "{$product->rating_count} avis"; // Vérifier la présence d'avis if ($product->has_ratings) { $distribution = $product->rating_distribution; // [1 => 2, 2 => 5, 3 => 10, 4 => 32, 5 => 78] }
📚 Référence de l'API
HasAvailabilityAttributes API
isAvailableNow(): Attribute<bool>
Vérifie si l'entité est disponible à l'instant présent.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<bool>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
if ($doctor->is_available_now) { // Le médecin est disponible }
nextSlot(): Attribute<SlotVO|null>
Retourne le prochain créneau disponible.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<SlotVO|null>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
$slot = $doctor->next_slot; if ($slot) { echo $slot->getStart()->toDateTimeString(); }
hasAvailabilityOnDate(): Attribute<bool>
Vérifie si l'entité a des disponibilités aujourd'hui.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<bool>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
if ($pharmacy->has_availability_on_date) { echo "La pharmacie est ouverte aujourd'hui"; }
totalAvailableMinutes(): Attribute<int>
Retourne le total des minutes disponibles aujourd'hui.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<int>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
$hours = $doctor->total_available_minutes / 60; echo "Disponible {$hours}h aujourd'hui";
HasRatingAttributes API
averageRating(): Attribute<float>
Retourne la note moyenne du modèle.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<float>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
echo $product->average_rating; // 4.5
ratingCount(): Attribute<int>
Retourne le nombre total d'évaluations.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<int>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
echo $product->rating_count; // 42
ratingDistribution(): Attribute<array<int, int>>
Retourne la distribution des notes par niveau (1 à 5).
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<array<int, int>>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
$distribution = $product->rating_distribution; // [1 => 0, 2 => 0, 3 => 1, 4 => 2, 5 => 5]
hasRatings(): Attribute<bool>
Indique si le modèle a au moins une évaluation.
| Paramètre | Type | Description |
|---|---|---|
| Aucun | - | - |
Retourne : Attribute<bool>
Exceptions : Aucune (les erreurs sont capturées)
Exemple :
if ($product->has_ratings) { // Afficher les évaluations }
🔍 Exemples complets
Modèle Doctor avec les deux traits
<?php declare(strict_types=1); namespace App\Models; use AndyDefer\Mixins\Traits\HasAvailabilityAttributes; use AndyDefer\Mixins\Traits\HasRatingAttributes; use Illuminate\Database\Eloquent\Model; final class Doctor extends Model { use HasAvailabilityAttributes; use HasRatingAttributes; protected $fillable = [ 'name', 'email', 'is_active', 'user_type', ]; protected function isSchedulable(): bool { return $this->is_active && $this->user_type === 'doctor'; } protected function isRateable(): bool { return $this->is_active && $this->user_type === 'doctor'; } }
Contrôleur d'API
<?php declare(strict_types=1); namespace App\Http\Controllers\Api; use App\Models\Doctor; use Illuminate\Http\JsonResponse; final class DoctorController { public function show(Doctor $doctor): JsonResponse { return response()->json([ 'id' => $doctor->id, 'name' => $doctor->name, 'email' => $doctor->email, 'available_now' => $doctor->is_available_now, 'next_slot' => $doctor->next_slot, 'has_availability_today' => $doctor->has_availability_on_date, 'available_minutes' => $doctor->total_available_minutes, 'average_rating' => $doctor->average_rating, 'rating_count' => $doctor->rating_count, 'rating_distribution' => $doctor->rating_distribution, 'has_ratings' => $doctor->has_ratings, ]); } }
Liste des médecins disponibles
$doctors = Doctor::all()->filter(fn($doctor) => $doctor->has_availability_on_date); foreach ($doctors as $doctor) { echo $doctor->name . ' - ' . $doctor->average_rating . '⭐'; }
🧪 Tests
Exécuter les tests
composer test
Exécuter uniquement les tests d'intégration
composer test-integration
Structure des tests
tests/
├── Fixtures/
│ ├── migrations/
│ │ └── 0001_00_00_000001_create_test_tables.php
│ └── Models/
│ ├── TestCar.php
│ ├── TestPost.php
│ └── TestUser.php
├── Integration/
│ └── Traits/
│ ├── HasAvailabilityAttributesTest.php
│ └── HasRatingAttributesTest.php
└── IntegrationTestCase.php
🔧 Développement
Style de code
./vendor/bin/pint
Analyse statique
./vendor/bin/phpstan analyse
🤝 Contribuer
Veuillez consulter CONTRIBUTING pour plus de détails.
Flux de développement
- Forkez le dépôt
- Créez une branche de fonctionnalité (
git checkout -b feature/amazing-feature) - Apportez vos modifications
- Exécutez les tests (
composer test) - Committez vos modifications (
git commit -m 'Ajouter une fonctionnalité géniale') - Poussez vers la branche (
git push origin feature/amazing-feature) - Ouvrez une Pull Request
📦 Dépendances
andydefer/laravel-chronos^1.0 - Moteur de planificationandydefer/laravel-ratings^1.0 - Système d'évaluation
👨💻 Auteur
Andy Defer
- GitHub: @andydefer
📄 Licence
Ce package est sous licence MIT. Voir le fichier LICENSE pour plus d'informations.
⭐ Support
Si vous trouvez ce package utile, n'hésitez pas à lui donner une ⭐ sur GitHub !
Construit avec ❤️ pour la communauté Laravel