PHPackages                             mawena/maravel - 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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. mawena/maravel

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

mawena/maravel
==============

Librairie Laravel avancée pour APIController avec système de permissions, modèles enrichis et policies automatiques

2.7.0(5mo ago)399MITPHPPHP ^8.1|^8.2|^8.3|^8.4CI failing

Since Oct 18Pushed 5mo agoCompare

[ Source](https://github.com/mawena/maravel)[ Packagist](https://packagist.org/packages/mawena/maravel)[ Docs](https://github.com/mawena/maravel)[ RSS](/packages/mawena-maravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (3)Versions (35)Used By (0)

Maravel
=======

[](#maravel)

[![Version](https://camo.githubusercontent.com/074981f12a524a1a9b7cfd22859c14b49ae834c8cd5ad85e698d56b199233132/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d322e372e302d626c75652e737667)](https://camo.githubusercontent.com/074981f12a524a1a9b7cfd22859c14b49ae834c8cd5ad85e698d56b199233132/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d322e372e302d626c75652e737667)[![PHP](https://camo.githubusercontent.com/29d537133f99f57b2a85cea7b429898685b9a83ef03d5180fb5879282e3a2840/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e31253743253545382e32253743253545382e33253743253545382e342d3737374242342e737667)](https://camo.githubusercontent.com/29d537133f99f57b2a85cea7b429898685b9a83ef03d5180fb5879282e3a2840/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e31253743253545382e32253743253545382e33253743253545382e342d3737374242342e737667)[![Laravel](https://camo.githubusercontent.com/ed8d06fb12d148f106ae2f9962d6bd0a6232e95b57092c88b505179c0563fc67/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25354531302e3025374325354531312e3025374325354531322e302d4646324432302e737667)](https://camo.githubusercontent.com/ed8d06fb12d148f106ae2f9962d6bd0a6232e95b57092c88b505179c0563fc67/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25354531302e3025374325354531312e3025374325354531322e302d4646324432302e737667)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)

**Maravel** est une librairie Laravel avancée qui accélère le développement d'API REST en fournissant un contrôleur générique avec CRUD complet, un système de permissions sophistiqué, des modèles enrichis avec formatage automatique, et des commandes Artisan pour générer du code prêt à l'emploi.

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

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

- [Fonctionnalités principales](#fonctionnalit%C3%A9s-principales)
- [Prérequis](#pr%C3%A9requis)
- [Installation](#installation)
- [Configuration](#configuration)
- [Démarrage rapide](#d%C3%A9marrage-rapide)
- [Utilisation avancée](#utilisation-avanc%C3%A9e)
    - [APIController](#apicontroller)
    - [ModelBase](#modelbase)
    - [BasePolicy](#basepolicy)
    - [Traits disponibles](#traits-disponibles)
    - [Commandes Artisan](#commandes-artisan)
- [Filtres avancés](#filtres-avanc%C3%A9s)
- [Système de permissions](#syst%C3%A8me-de-permissions)
- [Hooks et callbacks](#hooks-et-callbacks)
- [Exemples complets](#exemples-complets)
- [Tests](#tests)
- [Changelog](#changelog)
- [Contribution](#contribution)
- [License](#license)

---

Fonctionnalités principales
---------------------------

[](#fonctionnalités-principales)

### 🚀 APIController générique

[](#-apicontroller-générique)

- **CRUD complet** : Toutes les opérations (index, show, store, update, destroy) prêtes à l'emploi
- **Création multiple** : Méthode `store_multiple()` pour créer plusieurs enregistrements en une seule requête
- **Filtrage automatique** : Filtres basiques, min/max, IN/NOT IN, relations, recherche textuelle, JSON
- **Reducers personnalisés** : Transformations post-requête via méthodes reducer dans les modèles
- **Upload de gros fichiers** : Méthodes `uploadChunk()` et `mergeChunks()` pour fichiers volumineux
- **Pagination intelligente** : Pagination automatique ou désactivable avec paramètres configurables
- **Tri dynamique** : Tri ascendant/descendant sur n'importe quelle colonne
- **Gestion des relations** : Chargement automatique des relations Eloquent via paramètres d'URL

### 🔐 Système de permissions avancé

[](#-système-de-permissions-avancé)

- **BasePolicy** : Classe de base pour créer des policies sophistiquées
- **Permissions par profil** : Support des profils utilisateur (admin, user, etc.)
- **Règles d'abilités** : Système de règles avec sujets et actions (CASL-like)
- **PermissionCheckerTrait** : Méthodes helper pour vérifier les permissions facilement
- **Admin bypass** : Les administrateurs ont accès complet automatiquement

### 📦 ModelBase enrichi

[](#-modelbase-enrichi)

- **Formatage automatique des dates** : Conversion automatique avec localisation française
- **Formatage des montants** : Affichage des valeurs monétaires avec devise
- **Conversion des booléens** : Transformation en format lisible
- **Traduction des énumérations** : Support des enums avec traduction
- **Formatage des décimaux** : Notation française avec virgule
- **Big integers** : Conversion en int + formatage avec séparateurs de milliers (ex: 1 500 000)
- **Méthodes dynamiques** : Ajout de casts personnalisés à la volée

### 🛠️ Commandes Artisan

[](#️-commandes-artisan)

- `maravel:install` : Installe et configure automatiquement Maravel (API, AuthController, config)
- `make:maravel.controller` : Génère un contrôleur API complet avec CRUD, validation, hooks
- `make:maravel.model` : Génère un modèle avec ModelBase et formatage automatique
- `make:maravel.policy` : Génère une policy avancée avec système de permissions
- **Note** : Les commandes Laravel par défaut (`make:controller`, `make:model`, `make:policy`) restent disponibles

### ⚡ Traits réutilisables

[](#-traits-réutilisables)

- **ModelTrait** : Formatage automatique des données (dates, money, enums, booleans, big integers)
- **CustomResponseTrait** : Formatage standardisé des réponses JSON avec encodage UTF-8
- **ControllerHelperTrait** : Méthodes utilitaires pour les filtres, recherches, reducers et fichiers
- **PermissionCheckerTrait** : Vérification des permissions simplifiée
- **ScriptGeneratorTrait** : Génération de code automatique

---

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

[](#prérequis)

- **PHP** : 8.1, 8.2, 8.3 ou 8.4
- **Laravel** : 10.x, 11.x ou 12.x
- **Composer** : 2.x

---

Installation
------------

[](#installation)

Installez la librairie via Composer :

```
composer require mawena/maravel
```

Le service provider sera automatiquement enregistré grâce à l'auto-discovery de Laravel.

### Installation automatique

[](#installation-automatique)

Une fois la librairie installée, lancez la commande d'installation pour configurer automatiquement votre projet :

```
php artisan maravel:install
```

Cette commande effectue automatiquement les actions suivantes :

- 📦 Installation de Laravel Sanctum et configuration API (`php artisan install:api`)
- 🔐 Création du contrôleur `AuthController` dans `app/Http/Controllers/API/`
- 👥 Création du contrôleur `UserController` avec gestion du changement de mot de passe
- 🛡️ Création de la policy `UserPolicy` pour les permissions utilisateurs
- 🛣️ Configuration automatique du fichier `routes/api.php` avec les routes d'authentification et utilisateurs
- 👤 Création de la migration pour ajouter la colonne `profile` à la table `users`
- 🔒 Création de la migration pour ajouter les colonnes `activated` et `password_change_required`
- 🔧 Configuration du modèle `User` pour hériter de `AuthenticatableBase`
- 🛡️ Intégration du middleware `AccountStatusMiddleware` pour vérifier le statut des comptes
- ⚙️ Publication du fichier de configuration `config/advanced-api-controller.php`

#### ✨ Fusion intelligente des fichiers existants

[](#-fusion-intelligente-des-fichiers-existants)

**Nouvelle fonctionnalité (v2.6.0)** : La commande `maravel:install` utilise désormais un système de **fusion intelligente** pour préserver vos personnalisations :

- **Pas de remplacement destructif** : Si les fichiers `User.php`, `UserController.php`, `UserPolicy.php` ou `api.php` existent déjà, ils sont **fusionnés** au lieu d'être remplacés
- **Conservation de vos données** : Toutes vos méthodes, propriétés et routes personnalisées sont préservées
- **Priorité à la librairie** : En cas de conflit (même nom de méthode/propriété), la version de la librairie est utilisée pour garantir la compatibilité
- **Fusion intelligente** :
    - **Use statements** : Fusion sans doublons
    - **Traits** : Conservation et ajout des nouveaux
    - **Propriétés de classe** : Fusion avec priorité aux valeurs de la librairie
    - **Méthodes** : Ajout des nouvelles méthodes, mise à jour des existantes
    - **Routes** : Fusion des use statements si les routes existent déjà
- **Pas de confirmation** : L'installation est automatique et non-destructive

**Exemple** : Si vous avez déjà ajouté des méthodes personnalisées dans `UserController`, elles seront conservées lors de l'exécution de `maravel:install`, et les méthodes de la librairie (comme `updatePassword()`) seront ajoutées ou mises à jour.

Le contrôleur `AuthController` créé inclut les méthodes suivantes :

- `login()` : Authentification des utilisateurs
- `data()` : Récupération des données de l'utilisateur connecté
- `logout()` : Déconnexion de l'utilisateur

Le modèle `User` est automatiquement configuré avec :

- Héritage de `AuthenticatableBase` (au lieu de `Authenticatable`)
- Champ `profile` dans `$fillable`
- Champs `activated` et `password_change_required` dans `$fillable` (v2.5.3+)
- Casts d'énumération pour le profil (`admin` → Administrateur, `other` → Utilisateur)
- Casts booléens pour `activated` et `password_change_required`
- **Système de permissions via $enumCasts (v2.7.0+)** : Les `ability_rules` sont générées automatiquement via $enumCasts
- Labels français automatiques pour `profile`, `activated` et `password_change_required`

**Routes configurées automatiquement** dans `routes/api.php` :

```
use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\UserController;
use Illuminate\Support\Facades\Route;

Route::controller(AuthController::class)->group(function () {
    Route::post("auth/login", "login");

    Route::middleware('auth:sanctum')->group(function () {
        Route::prefix("/auth")->name("auth.")->group(function () {
            Route::get('data', "data")->name("data");
            Route::delete('logout', "logout")->name("logout");
        });

        // Route pour changer le mot de passe (accessible même si password_change_required)
        Route::put('users/update-password', [UserController::class, 'updatePassword'])
            ->name('user.update-password');

        // Routes protégées par le middleware de statut de compte
        Route::middleware('account.status')->group(function () {
            // Routes utilisateurs CRUD
            Route::prefix('users')->name('user.')->controller(UserController::class)->group(function () {
                Route::get('/', 'index')->name('index');
                Route::post('/', 'store')->name('store');
                Route::get('/{id}', 'show')->name('show');
                Route::put('/{id}', 'update')->name('update');
                Route::delete('/{id}', 'destroy')->name('destroy');
            });

            // Routes supplémentaires sous autorisation
        });
    });
});
```

**Endpoints disponibles** :

- `POST /api/auth/login` - Connexion
- `GET /api/auth/data` - Données utilisateur (authentifié)
- `DELETE /api/auth/logout` - Déconnexion (authentifié)
- `PUT /api/users/update-password` - Changer le mot de passe (authentifié, toujours accessible)
- `GET /api/users` - Liste des utilisateurs (authentifié + statut actif)
- `POST /api/users` - Créer un utilisateur (authentifié + statut actif)
- `GET /api/users/{id}` - Voir un utilisateur (authentifié + statut actif)
- `PUT /api/users/{id}` - Modifier un utilisateur (authentifié + statut actif)
- `DELETE /api/users/{id}` - Supprimer un utilisateur (authentifié + statut actif)

**Migrations créées** :

1. `xxxx_xx_xx_xxxxxx_add_profile_to_users_table.php`

```
Schema::table('users', function (Blueprint $table) {
    $table->enum('profile', ['admin', 'other'])->default('other')->after('email');
});
```

2. `xxxx_xx_xx_xxxxxx_add_account_status_to_users_table.php` (v2.5.3+)

```
Schema::table('users', function (Blueprint $table) {
    $table->boolean('activated')->default(true)->after('profile');
    $table->boolean('password_change_required')->default(false)->after('activated');
});
```

**Système de permissions (v2.7.0+)** : Le modèle User est configuré avec un système de permissions basé sur les profils via $enumCasts :

- **admin** : Accès complet à toutes les ressources (`['subject' => ['all'], 'action' => ['manage']]`)
- **other** : Permissions limitées (lecture utilisateur uniquement)

Vous pouvez étendre les permissions en modifiant le $enumCasts correspondant dans `app/Models/User.php`. Les `ability_rules` sont maintenant générées automatiquement via le système de casts unifié.

**Gestion du statut des comptes** (v2.5.3+) :

Le middleware `AccountStatusMiddleware` (alias : `account.status`) vérifie automatiquement :

- **activated = false** : Bloque l'accès avec le message "Votre compte est désactivé"
- **password\_change\_required = true** : Bloque l'accès avec le message "Vous devez changer votre mot de passe" (sauf pour la route `/users/update-password`)

Ce middleware est automatiquement appliqué aux routes CRUD des utilisateurs, mais pas à la route de changement de mot de passe, permettant ainsi aux utilisateurs de changer leur mot de passe même si `password_change_required` est à `true`.

### Publication manuelle de la configuration (optionnel)

[](#publication-manuelle-de-la-configuration-optionnel)

Si vous souhaitez uniquement publier le fichier de configuration sans exécuter l'installation complète :

```
php artisan vendor:publish --provider="Maravel\Providers\AdvancedApiControllerServiceProvider" --tag="advanced-api-controller-config"
```

Cela créera le fichier `config/advanced-api-controller.php`.

---

Configuration
-------------

[](#configuration)

Le fichier de configuration `config/advanced-api-controller.php` vous permet de personnaliser :

### Defaults (Paramètres par défaut)

[](#defaults-paramètres-par-défaut)

```
'defaults' => [
    'pagination' => [
        'per_page' => 8,           // Nombre d'éléments par page
        'max_per_page' => 100,     // Maximum d'éléments par page
    ],
    'validation' => [
        'store' => [],             // Règles de validation par défaut pour store
        'update' => [],            // Règles de validation par défaut pour update
    ],
    'authorization' => [
        'ability_read' => 'read',
        'ability_create' => 'create',
        'ability_update' => 'update',
        'ability_delete' => 'delete',
    ],
],
```

### Filters (Configuration des filtres)

[](#filters-configuration-des-filtres)

```
'filters' => [
    'enabled' => true,
    'types' => [
        'basic' => true,           // Filtres basiques: ?name=value
        'min_max' => true,         // Filtres min/max: ?min true,       // Filtres IN/NOT IN: ?in_status=active-pending
        'relations' => true,       // Filtres sur relations
        'search' => true,          // Recherche textuelle: ?search=keyword
        'json' => true,            // Filtres JSON
    ],
],
```

### Models (Configuration des modèles)

[](#models-configuration-des-modèles)

```
'models' => [
    'use_model_base' => true,
    'date_format' => 'd/m/Y H:i:s',
    'money_format' => [
        'currency' => 'XOF',
        'decimal_separator' => ',',
        'thousands_separator' => ' ',
    ],
    'auto_casts' => [
        'created_at' => true,
        'updated_at' => true,
    ],
],
```

### Permissions (Configuration des permissions)

[](#permissions-configuration-des-permissions)

```
'permissions' => [
    'enabled' => true,
    'use_advanced_policies' => true,
    'admin_profile' => 'admin',
    'check_permissions' => true,
],
```

---

Démarrage rapide
----------------

[](#démarrage-rapide)

### 1. Créer un contrôleur

[](#1-créer-un-contrôleur)

```
php artisan make:maravel.controller ProductController
```

### 2. Définir le modèle et la validation

[](#2-définir-le-modèle-et-la-validation)

```
namespace App\Http\Controllers\API;

use Maravel\Http\Controllers\APIController;
use App\Models\Product;

class ProductController extends APIController
{
    protected string $modelClass = Product::class;

    protected array $storeValidationArray = [
        'name' => 'required|string|max:255',
        'price' => 'required|numeric|min:0',
        'stock' => 'required|integer|min:0',
    ];

    protected array $updateValidationArray = [
        'name' => 'string|max:255',
        'price' => 'numeric|min:0',
        'stock' => 'integer|min:0',
    ];

    protected array $indexSearchFieldList = ['name', 'description'];
}
```

### 3. Créer les routes

[](#3-créer-les-routes)

```
use App\Http\Controllers\API\ProductController;

Route::apiResource('products', ProductController::class);
```

### 4. C'est prêt!

[](#4-cest-prêt)

Votre API est maintenant opérationnelle avec :

- **GET** `/api/products` - Liste tous les produits
- **GET** `/api/products/{id}` - Affiche un produit
- **POST** `/api/products` - Crée un produit
- **PUT/PATCH** `/api/products/{id}` - Modifie un produit
- **DELETE** `/api/products/{id}` - Supprime un produit

---

Utilisation avancée
-------------------

[](#utilisation-avancée)

### APIController

[](#apicontroller)

Le contrôleur de base fournit toutes les méthodes CRUD et de nombreuses options de personnalisation.

#### Propriétés disponibles

[](#propriétés-disponibles)

```
class ProductController extends APIController
{
    // OBLIGATOIRE : Classe du modèle Eloquent
    protected string $modelClass = Product::class;

    // Validation pour la création
    protected array $storeValidationArray = [];

    // Validation pour la mise à jour
    protected array $updateValidationArray = [];

    // Champs de recherche textuelle
    protected array $indexSearchFieldList = [];

    // Relations à charger automatiquement
    protected array $indexWithArray = [];
    protected array $showWithArray = [];

    // Nom de l'abilité pour les permissions
    protected string $readAbilityName = 'read';
    protected string $createAbilityName = 'create';
    protected string $updateAbilityName = 'update';
    protected string $deleteAbilityName = 'delete';

    // Activation/désactivation des permissions
    protected bool $indexCheckAbility = true;
    protected bool $showCheckAbility = true;
    protected bool $storeCheckAbility = true;
    protected bool $updateCheckAbility = true;
    protected bool $deleteCheckAbility = true;
}
```

#### Méthodes disponibles

[](#méthodes-disponibles)

- `index(Request $request)` : Liste les ressources avec filtrage, recherche, tri, pagination
- `show($id, Request $request)` : Affiche une ressource spécifique
- `store(Request $request)` : Crée une nouvelle ressource
- `store_multiple(Request $request)` : Crée plusieurs ressources en une fois
- `update(Request $request, $id)` : Met à jour une ressource
- `destroy($id)` : Supprime une ressource

#### Gestion des uploads de gros fichiers

[](#gestion-des-uploads-de-gros-fichiers)

L'APIController inclut des méthodes pour gérer l'upload de fichiers volumineux par chunks (morceaux) :

##### uploadChunk()

[](#uploadchunk)

Permet de télécharger un fichier volumineux en plusieurs morceaux :

```
// Route : POST /api/upload-chunk
// Paramètres :
// - file: Le morceau de fichier (UploadedFile)
// - index: L'index du morceau (string/int)
// - filename: Le nom du fichier complet

// Exemple d'utilisation côté client (JavaScript) :
const uploadFile = async (file) => {
    const chunkSize = 1024 * 1024; // 1MB par chunk
    const chunks = Math.ceil(file.size / chunkSize);

    for (let i = 0; i < chunks; i++) {
        const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
        const formData = new FormData();
        formData.append('file', chunk);
        formData.append('index', i);
        formData.append('filename', file.name);

        await fetch('/api/upload-chunk', {
            method: 'POST',
            body: formData
        });
    }
};
```

##### mergeChunks()

[](#mergechunks)

Fusionne tous les morceaux uploadés en un seul fichier :

```
// Route : POST /api/merge-chunks
// Paramètres :
// - filename: Le nom du fichier à fusionner

// Retourne :
// {
//   "status": "file merged",
//   "file_path": "uploads/1234567890/mon-fichier.pdf"
// }

// Exemple d'utilisation :
Route::post('/upload-chunk', [MyController::class, 'uploadChunk']);
Route::post('/merge-chunks', [MyController::class, 'mergeChunks']);
```

**Fonctionnalités** :

- Stockage temporaire des chunks dans `storage/app/tmp/`
- Fusion sécurisée avec verrouillage de fichier
- Nettoyage automatique des fichiers temporaires
- Nom de fichier sécurisé (slug + extension)
- Stockage final dans `storage/app/public/uploads/{timestamp}/`

**Sécurité** :

- Validation des chunks
- Tri numérique correct des morceaux
- Gestion des erreurs de lecture/écriture
- Suppression récursive des répertoires temporaires

---

### ModelBase

[](#modelbase)

Utilisez `ModelBase` comme classe parente pour vos modèles afin de bénéficier du formatage automatique.

```
namespace App\Models;

use Maravel\Models\ModelBase;

class Product extends ModelBase
{
    protected $fillable = ['name', 'price', 'stock', 'description', 'views_count'];

    // Définir les casts personnalisés
    protected array $dateCasts = [
        'published_at' => 'd/m/Y',  // Format personnalisé
    ];

    protected array $moneyCasts = [
        'price',                     // Formaté avec la config par défaut
    ];

    protected array $booleanCasts = [
        'is_active',                 // Formaté en 'Oui'/'Non'
    ];

    protected array $big_integer_casts = [
        'views_count',               // Converti en int + formaté avec espaces
    ];

    protected array $enumCasts = [
        [
            'colum_name' => 'status',
            'choices' => [
                'active' => 'Actif',
                'inactive' => 'Inactif',
                'pending' => 'En attente',
            ],
            'additional_column_name' => 'status_label',
        ],
    ];
}
```

#### Structure de $enumCasts (v2.6.8+)

[](#structure-de-enumcasts-v268)

Depuis la version 2.6.8, la structure de `$enumCasts` a été améliorée pour offrir plus de flexibilité. Chaque élément est maintenant un tableau associatif avec les clés suivantes :

```
protected array $enumCasts = [
    [
        'colum_name' => 'status',                    // Nom de la colonne dans la base de données
        'choices' => [                                // Mapping valeur => label
            'active' => 'Actif',
            'inactive' => 'Inactif',
            'pending' => 'En attente',
        ],
        'additional_column_name' => 'status_label',   // Nom de l'attribut formaté dans le JSON
    ],
    [
        'colum_name' => 'priority',
        'choices' => [
            'low' => 'Basse',
            'medium' => 'Moyenne',
            'high' => 'Haute',
        ],
        'additional_column_name' => 'priority_text',
    ],
];
```

**Avantages de cette structure** :

- ✅ Personnalisation du nom de la colonne formatée (au lieu du suffixe `_fr` automatique)
- ✅ Support de plusieurs énumérations dans un même modèle
- ✅ Plus de clarté et de lisibilité dans la configuration

**Exemple de résultat JSON** :

```
$product = Product::find(1);
// Si $product->status = 'active'

$product->toArray();
// Retourne :
[
    'id' => 1,
    'status' => 'active',              // Valeur brute
    'status_label' => 'Actif',         // Valeur formatée avec le nom personnalisé
    'priority' => 'high',
    'priority_text' => 'Haute',
    // ...
]
```

#### Méthodes dynamiques

[](#méthodes-dynamiques)

Ajoutez des casts à la volée :

```
$product = Product::find(1);

// Ajouter un cast date
$product->addDateCast('last_order_at', 'd/m/Y H:i');

// Ajouter un cast money
$product->addMoneyCast('cost');

// Ajouter un cast enum
$product->addEnumCast('type', [
    'physical' => 'Produit physique',
    'digital' => 'Produit numérique',
]);
```

#### Attributs automatiques

[](#attributs-automatiques)

Les attributs suivants sont automatiquement ajoutés :

- `created_at_fr` : Date de création formatée
- `updated_at_fr` : Date de mise à jour formatée
- `{field}_formatted` : Version formatée des booléens
- `{field}_fr` : Version formatée des dates, montants, floats et big integers
- `{additional_column_name}` : Version formatée des énumérations avec nom personnalisable (défini dans `$enumCasts`)

Exemple avec big\_integer\_casts :

```
$product = Product::find(1);
// $product->views_count => 1500000 (int)
// $product->views_count_fr => "1 500 000" (string formatée)
```

Exemple avec booleanCasts (v2.6.9+) :

```
$product = Product::find(1);
$product->toArray();
// Retourne :
[
    'is_active' => 1,              // Valeur convertie en int (0 ou 1)
    'is_active_formatted' => true, // Valeur booléenne (true ou false)
]
```

**Note** : Depuis la version 2.6.9, les booléens sont automatiquement convertis en entiers (0 ou 1) pour améliorer la compatibilité avec les APIs et bases de données qui attendent des valeurs numériques.

---

### ModelTrait

[](#modeltrait)

Le coeur du système de formatage. Ce trait est utilisé par `ModelBase` et `AuthenticatableBase`.

#### Fonctionnalités du trait

[](#fonctionnalités-du-trait)

```
use Maravel\Models\ModelTrait;

class MyModel extends Model
{
    use ModelTrait;

    protected $dateCasts = ['published_at' => 'd/m/Y'];
    protected $moneyCasts = ['price', 'cost'];
    protected $booleanCasts = ['is_active'];
    protected $big_integer_casts = ['views_count', 'total_sales'];
    protected $floatCasts = ['rating'];
    protected $enumCasts = [
        [
            'colum_name' => 'status',
            'choices' => ['draft' => 'Brouillon', 'published' => 'Publié'],
            'additional_column_name' => 'status_label'
        ]
    ];
}
```

#### Méthodes disponibles

[](#méthodes-disponibles-1)

- `addDateCast($column, $format)` : Ajoute un cast de date dynamiquement
- `addMoneyCast($column)` : Ajoute un cast monétaire dynamiquement
- `addBooleanCast($column)` : Ajoute un cast booléen dynamiquement
- `addEnumCast($column, $choices)` : Ajoute un cast enum dynamiquement
- `addFloatCast($column)` : Ajoute un cast float dynamiquement
- `addBigIntegerCast($column)` : Ajoute un cast big integer dynamiquement (conversion en int + formatage avec espaces)

#### Détails des casts

[](#détails-des-casts)

##### big\_integer\_casts

[](#big_integer_casts)

Convertit les grands entiers en int et ajoute une version formatée avec séparateurs de milliers :

```
protected $big_integer_casts = ['views_count', 'total_sales'];

// Résultat dans toArray() :
// 'views_count' => 1500000        // Converti en int
// 'views_count_fr' => '1 500 000' // Version formatée
```

#### Utilisation directe du trait

[](#utilisation-directe-du-trait)

Vous pouvez utiliser `ModelTrait` directement sans hériter de `ModelBase` :

```
use Illuminate\Database\Eloquent\Model;
use Maravel\Models\ModelTrait;

class Product extends Model
{
    use ModelTrait; // Utilisation directe du trait

    protected $dateCasts = ['launched_at' => 'd/m/Y'];
    protected $moneyCasts = ['price'];
}
```

---

### AuthenticatableBase

[](#authenticatablebase)

Pour les modèles nécessitant l'authentification (comme User), Maravel fournit `AuthenticatableBase`.

#### Créer un modèle User

[](#créer-un-modèle-user)

```
php artisan make:maravel.model User --authenticatable -m
```

#### Exemple de modèle User

[](#exemple-de-modèle-user)

```
namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Maravel\Models\AuthenticatableBase;

class User extends AuthenticatableBase
{
    use HasApiTokens, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
        'profile',
        'activated',
        'password_change_required',
    ];

    protected $hidden = ['password', 'remember_token'];

    // Casts d'énumération pour le profil et les permissions (v2.7.0+)
    protected $enumCasts = [
        [
            'colum_name' => 'profile',
            'additional_column_name' => 'profile_fr',
            'choices' => [
                'admin' => 'Administrateur',
                'other' => 'Utilisateur',
            ],
        ],
        [
            'colum_name' => 'profile',
            'additional_column_name' => 'ability_rules',
            'choices' => [
                'admin' => [
                    [
                        'subject' => ['all'],
                        'action' => ['manage'],
                    ],
                ],
                'other' => [
                    [
                        'subject' => ['user'],
                        'action' => ['read'],
                    ],
                ],
            ],
        ],
        [
            'colum_name' => 'activated',
            'additional_column_name' => 'activated_fr',
            'choices' => [
                1 => 'Oui',
                0 => 'Non',
            ],
        ],
        [
            'colum_name' => 'password_change_required',
            'additional_column_name' => 'password_change_required_fr',
            'choices' => [
                1 => 'Oui',
                0 => 'Non',
            ],
        ],
    ];

    /**
     * Get the attributes that should be cast.
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'activated' => 'boolean',
            'password_change_required' => 'boolean',
        ];
    }

    /**
     * Vérifie si l'utilisateur est administrateur
     */
    public function isAdmin(): bool
    {
        return $this->profile === 'admin';
    }
}
```

#### Avantages d'AuthenticatableBase

[](#avantages-dauthenticatablebase)

- ✅ **Compatible avec l'authentification Laravel** : Étend `Illuminate\Foundation\Auth\User`
- ✅ **Formatage automatique** : Utilise ModelTrait pour les mêmes fonctionnalités que ModelBase
- ✅ **Support Sanctum** : Compatible avec Laravel Sanctum pour les API
- ✅ **Permissions intégrées** : Système d'abilités prêt à l'emploi
- ✅ **Méthodes utilitaires** : isAdmin(), hasProfile() générées automatiquement

#### Architecture

[](#architecture)

```
ModelTrait (trait commun)
    ├── ModelBase (pour modèles standards)
    │   └── extends Model
    │
    └── AuthenticatableBase (pour authentification)
        └── extends Authenticatable

```

Les deux classes utilisent le même trait `ModelTrait`, évitant ainsi la duplication de code.

---

### Gestion des utilisateurs et sécurité des comptes

[](#gestion-des-utilisateurs-et-sécurité-des-comptes)

Maravel inclut un système complet de gestion des utilisateurs avec contrôle du statut des comptes (v2.5.3+).

#### UserController

[](#usercontroller)

Le contrôleur `UserController` est automatiquement créé lors de l'installation et inclut :

- **Opérations CRUD complètes** : Liste, création, modification, suppression des utilisateurs
- **Méthode updatePassword()** : Permet aux utilisateurs de changer leur mot de passe
- **Validation automatique** : Règles de validation pour création et modification
- **Hachage des mots de passe** : Les mots de passe sont automatiquement hachés
- **Gestion du statut** : Support des champs `activated` et `password_change_required`

**Méthode updatePassword** :

```
// Route : PUT /api/users/update-password
// Corps de la requête :
{
    "current_password": "ancien_mot_de_passe",
    "new_password": "nouveau_mot_de_passe",
    "new_password_confirmation": "nouveau_mot_de_passe"
}

// Réponse en cas de succès :
{
    "message": "Mot de passe modifié avec succès",
    "user": { ... }
}
```

Cette méthode :

- Vérifie que le mot de passe actuel est correct
- Valide le nouveau mot de passe (minimum 8 caractères)
- Vérifie que la confirmation correspond
- Met automatiquement `password_change_required` à `false` après changement

#### AccountStatusMiddleware

[](#accountstatusmiddleware)

Le middleware `AccountStatusMiddleware` (alias : `account.status`) vérifie le statut du compte utilisateur avant d'autoriser l'accès aux routes protégées.

**Vérifications effectuées** :

1. **Compte désactivé** (`activated = false`) :

    ```
    {
        "error": "Votre compte est désactivé. Veuillez contacter l'administrateur."
    }
    ```

    Code HTTP : 403
2. **Changement de mot de passe requis** (`password_change_required = true`) :

    ```
    {
        "error": "Vous devez changer votre mot de passe avant de continuer."
    }
    ```

    Code HTTP : 403

**Important** : Le middleware n'est PAS appliqué à la route `/users/update-password`, permettant aux utilisateurs de changer leur mot de passe même si `password_change_required = true`.

#### Utilisation du middleware

[](#utilisation-du-middleware)

Le middleware est automatiquement configuré dans `bootstrap/app.php` :

```
->withMiddleware(function (Middleware $middleware) {
    // Middleware Maravel pour vérifier le statut du compte
    $middleware->alias([
        'account.status' => \Maravel\Http\Middleware\AccountStatusMiddleware::class,
    ]);
})
```

Appliquez-le sur vos routes :

```
// Sur un groupe de routes
Route::middleware(['auth:sanctum', 'account.status'])->group(function () {
    Route::apiResource('posts', PostController::class);
    Route::apiResource('products', ProductController::class);
});

// Sur une route spécifique
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware(['auth:sanctum', 'account.status']);
```

#### Scénarios d'utilisation

[](#scénarios-dutilisation)

**1. Désactiver un utilisateur** :

```
$user = User::find(5);
$user->activated = false;
$user->save();
// L'utilisateur ne pourra plus accéder aux routes protégées par account.status
```

**2. Forcer le changement de mot de passe** :

```
$user = User::find(5);
$user->password_change_required = true;
$user->save();
// L'utilisateur devra changer son mot de passe avant d'accéder aux routes protégées
```

**3. Réactiver un compte** :

```
$user = User::find(5);
$user->activated = true;
$user->password_change_required = false;
$user->save();
// L'utilisateur retrouve un accès complet
```

---

### BasePolicy

[](#basepolicy)

Créez des policies avancées avec système de permissions.

#### Créer une policy

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

```
php artisan make:maravel.policy ProductPolicy
```

#### Exemple de policy

[](#exemple-de-policy)

```
namespace App\Policies;

use Maravel\Policies\BasePolicy;
use App\Models\User;
use App\Models\Product;

class ProductPolicy extends BasePolicy
{
    // Le sujet pour les vérifications de permissions
    protected string $subject = 'product';

    // Méthode before() pour vérifications globales
    public function before(User $user, string $ability): ?bool
    {
        // Les admins ont tous les droits
        if ($user->profile === 'admin') {
            return true;
        }

        return null; // Continuer les vérifications normales
    }

    // Permission personnalisée
    public function publish(User $user, Product $product): bool
    {
        return $this->checkCustomPermission($user, ['publish'], $this->subject)
            && $product->user_id === $user->id;
    }
}
```

#### Enregistrer la policy

[](#enregistrer-la-policy)

Dans `AuthServiceProvider.php` :

```
use App\Models\Product;
use App\Policies\ProductPolicy;

protected $policies = [
    Product::class => ProductPolicy::class,
];
```

---

### Traits disponibles

[](#traits-disponibles)

#### CustomResponseTrait

[](#customresponsetrait)

Formatage standardisé des réponses JSON :

```
use Maravel\Http\Traits\CustomResponseTrait;

class MyController extends Controller
{
    use CustomResponseTrait;

    public function index()
    {
        $data = ['items' => [...]];
        return $this->responseOk($data, ['Success'], 200);
    }

    public function error()
    {
        return $this->responseError(['field' => ['Error message']], 400);
    }
}
```

#### ControllerHelperTrait

[](#controllerhelpertrait)

Méthodes utilitaires pour les contrôleurs :

```
use Maravel\Http\Traits\ControllerHelperTrait;

class MyController extends Controller
{
    use ControllerHelperTrait;

    public function index(Request $request)
    {
        $query = Product::query();

        // Ajouter des filtres
        $query = $this->queryFilter($query, $request->all(), 'Product');

        // Ajouter recherche
        $query = $this->querySearch($query, ['name', 'description'], $request->search);

        // Ajouter relations
        $query = $this->queryRelationAdd($query, $request->all(), 'Product');

        return $query->get();
    }
}
```

##### Reducers personnalisés

[](#reducers-personnalisés)

Le trait fournit également `reduceCollection()` qui permet d'appliquer des transformations personnalisées sur une collection après une requête SQL :

```
// Dans votre modèle, définissez des méthodes "reducer"
class Product extends ModelBase
{
    /**
     * Reducer pour ajouter des statistiques
     */
    public function statsReducer($collection, $requestData)
    {
        // Ajouter des statistiques calculées
        $collection->map(function ($item) {
            $item->total_revenue = $item->price * $item->sold_count;
            return $item;
        });

        return $collection;
    }

    /**
     * Reducer pour filtrer selon l'utilisateur
     */
    public function userFilterReducer($collection, $requestData)
    {
        $userId = $requestData['user_id'] ?? null;
        if ($userId) {
            return $collection->where('user_id', $userId)->values();
        }
        return $collection;
    }
}

// Utilisation dans la requête API :
// GET /api/products?reduce_stats=true
// GET /api/products?reduce_user_filter=true&user_id=5

// Le système cherchera automatiquement les méthodes suffixées par "Reducer"
```

Les reducers sont automatiquement appliqués par l'APIController après l'exécution de la requête SQL, permettant des transformations complexes sans surcharger la requête.

#### PermissionCheckerTrait

[](#permissioncheckertrait)

Vérification simplifiée des permissions :

```
use Maravel\Http\Traits\PermissionCheckerTrait;

class MyController extends Controller
{
    use PermissionCheckerTrait;

    public function index(Request $request)
    {
        $user = $request->user();

        if (!$this->canRead('product', $user)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        if ($this->isAdmin($user)) {
            // Logique admin
        }

        return Product::all();
    }
}
```

---

### Commandes Artisan

[](#commandes-artisan)

Maravel fournit plusieurs commandes personnalisées qui **coexistent** avec les commandes Laravel standard. Les commandes par défaut (`make:controller`, `make:policy`) restent disponibles et fonctionnelles.

#### maravel:install

[](#maravelinstall)

Installe et configure automatiquement Maravel dans votre projet Laravel :

```
php artisan maravel:install
```

**Ce qui est exécuté automatiquement** :

- ✅ Installation de Laravel Sanctum et configuration API (`php artisan install:api`)
- ✅ Création du contrôleur AuthController dans `app/Http/Controllers/API/`
- ✅ Création du contrôleur UserController avec méthode `updatePassword()` (v2.5.3+)
- ✅ Création de la policy UserPolicy pour les permissions utilisateurs (v2.5.3+)
- ✅ Configuration automatique des routes d'authentification et utilisateurs dans `routes/api.php`
- ✅ Création de la migration pour ajouter la colonne `profile` (enum: admin, other)
- ✅ Création de la migration pour `activated` et `password_change_required` (v2.5.3+)
- ✅ Configuration du modèle User avec AuthenticatableBase et système de permissions
- ✅ Intégration du middleware `AccountStatusMiddleware` dans `bootstrap/app.php` (v2.5.3+)
- ✅ Publication du fichier de configuration `config/advanced-api-controller.php`
- ✅ **Fusion intelligente** des fichiers existants (v2.6.0+) : Vos personnalisations sont préservées

**Avantages** :

- Configuration rapide et sans erreur
- AuthController prêt à l'emploi avec login, logout et récupération des données utilisateur
- Routes d'authentification configurées automatiquement (plus besoin de les ajouter manuellement)
- Support complet de Laravel Sanctum pour l'authentification API
- Structure de routes organisée avec groupes et préfixes
- Système de permissions prêt à l'emploi avec profils utilisateur (admin, user)
- Modèle User configuré avec AuthenticatableBase et ability\_rules
- **Fusion non-destructive** : Vos méthodes et propriétés personnalisées sont conservées
- **Installation répétable** : Vous pouvez relancer la commande pour mettre à jour sans perte de données

**Recommandation** : Lancez cette commande immédiatement après `composer require mawena/maravel` pour configurer votre projet en une seule commande. Vous pouvez aussi la relancer après une mise à jour de la librairie pour bénéficier des nouvelles fonctionnalités sans perdre vos personnalisations.

#### make:maravel.controller

[](#makemaravelcontroller)

Génère un contrôleur API complet avec APIController :

```
php artisan make:maravel.controller ProductController
```

**Ce qui est généré** :

- Toutes les méthodes CRUD prêtes à l'emploi
- Système de validation avancé
- Hooks (before/after create, update, delete)
- Documentation PHPDoc complète
- Gestion des permissions intégrée
- Support automatique des filtres et pagination

**Emplacement** : `App\Http\Controllers\API\ProductController.php`

#### make:maravel.model

[](#makemaravelmodel)

Génère un modèle avec ModelBase ou AuthenticatableBase :

```
# Modèle standard avec ModelBase
php artisan make:maravel.model Product

# Modèle User avec AuthenticatableBase (pour l'authentification)
php artisan make:maravel.model User --authenticatable
```

**Ce qui est généré** :

- Extension de ModelBase (ou AuthenticatableBase avec option `-a`)
- Formatage automatique des dates (created\_at\_fr, updated\_at\_fr)
- Support des casts personnalisés ($dateCasts, $moneyCasts, $enumCasts, $booleanCasts)
- Relations Eloquent commentées (exemples)
- Scopes commentés (exemples)
- Méthodes utilitaires (pour User: isAdmin(), hasProfile())

**Emplacement** : `App\Models\Product.php`

**Options disponibles** :

- `-m` ou `--migration` : Crée automatiquement la migration
- `-c` ou `--controller` : Crée automatiquement le contrôleur API
- `-p` ou `--policy` : Crée automatiquement la policy
- `-a` ou `--authenticatable` : Crée un modèle Authenticatable (User)
- `--all` : Crée migration, contrôleur et policy en une seule commande

**Exemples** :

```
# Créer un modèle avec migration
php artisan make:maravel.model Product -m

# Créer un modèle avec tout (migration, controller, policy)
php artisan make:maravel.model Product --all

# Créer un modèle User avec authentification
php artisan make:maravel.model User --authenticatable -m

# Créer un modèle avec controller et policy
php artisan make:maravel.model Post -cp
```

#### make:maravel.policy

[](#makemaravelpolicy)

Génère une policy avancée avec BasePolicy :

```
php artisan make:maravel.policy ProductPolicy
```

**Ce qui est généré** :

- Toutes les méthodes de permissions (viewAny, view, create, update, delete, restore, forceDelete)
- Méthode `before()` pour vérifications globales
- Support des permissions personnalisées
- Système de règles d'abilités
- Documentation PHPDoc complète

**Emplacement** : `App\Policies\ProductPolicy.php`

#### Différence avec les commandes Laravel standard

[](#différence-avec-les-commandes-laravel-standard)

CommandeDescription`maravel:install`**Commande unique Maravel** - installe et configure automatiquement Maravel (API + AuthController + config)`make:controller`Commande Laravel standard - génère un contrôleur vide`make:maravel.controller`Commande Maravel - génère un contrôleur API complet avec APIController`make:model`Commande Laravel standard - génère un modèle basique`make:maravel.model`Commande Maravel - génère un modèle avec ModelBase et formatage automatique`make:policy`Commande Laravel standard - génère une policy basique`make:maravel.policy`Commande Maravel - génère une policy avancée avec BasePolicy#### Exemples d'utilisation complète

[](#exemples-dutilisation-complète)

```
# Installation initiale de Maravel
composer require mawena/maravel
php artisan maravel:install  # Configure automatiquement l'API et crée AuthController

# Workflow complet : Créer un modèle avec tout
php artisan make:maravel.model Product --all
# Cela crée : Model + Migration + Controller + Policy

# Workflow étape par étape
php artisan make:maravel.model Product -m        # Modèle + Migration
php artisan make:maravel.controller Product      # Contrôleur
php artisan make:maravel.policy Product          # Policy

# Créer un contrôleur dans un sous-dossier
php artisan make:maravel.controller API/V2/ProductController

# Créer un modèle User avec authentification
php artisan make:maravel.model User -a -m

# Workflow pour un modèle de blog complet
php artisan make:maravel.model Post --all
# Éditer la migration, puis :
php artisan migrate
```

---

Filtres avancés
---------------

[](#filtres-avancés)

L'APIController supporte plusieurs types de filtres via l'URL :

### Filtres basiques

[](#filtres-basiques)

Filtrer par égalité :

```
GET /api/products?name=iPhone&category_id=2

```

### Filtres min/max

[](#filtres-minmax)

Filtrer par plage de valeurs :

```
GET /api/products?min 10000) {
            return ['price' => ['Le prix ne peut pas dépasser 10000']];
        }
        return [];
    }

    // Avant la création
    protected function storeBeforeCreateFunction(array $data): array
    {
        $data['slug'] = Str::slug($data['name']);
        return $data;
    }

    // Après la création
    protected function storeAfterCreateFunction($model): void
    {
        // Envoyer un email
        Mail::to('admin@example.com')->send(new ProductCreated($model));
    }

    // Avant le commit en base de données
    protected function storeBeforeCommitFunction($model): void
    {
        // Logique métier
    }

    // Après le commit
    protected function storeAfterCommitFunction($model): void
    {
        // Créer des enregistrements liés
        $model->history()->create(['action' => 'created']);
    }
}
```

### Hooks de mise à jour

[](#hooks-de-mise-à-jour)

```
class ProductController extends APIController
{
    // Validation personnalisée
    protected function updateManualValidationsFunction(array $data, $model): array
    {
        if (isset($data['price']) && $data['price'] < $model->cost) {
            return ['price' => ['Le prix ne peut pas être inférieur au coût']];
        }
        return [];
    }

    // Avant la mise à jour
    protected function updateBeforeUpdateFunction(array $data, $model): array
    {
        if (isset($data['name'])) {
            $data['slug'] = Str::slug($data['name']);
        }
        return $data;
    }

    // Après la mise à jour
    protected function updateAfterUpdateFunction($model): void
    {
        Cache::forget("product_{$model->id}");
    }
}
```

### Hooks de suppression

[](#hooks-de-suppression)

```
class ProductController extends APIController
{
    // Avant la suppression
    protected function deleteBeforeDeleteFunction($model): void
    {
        // Supprimer les fichiers associés
        Storage::delete($model->images->pluck('path')->toArray());
    }

    // Après la suppression
    protected function deleteAfterDeleteFunction($model): void
    {
        // Logger la suppression
        Log::info("Product {$model->id} deleted");
    }
}
```

### Filtre manuel sur index

[](#filtre-manuel-sur-index)

```
class ProductController extends APIController
{
    protected function indexManualFilter($query, array $requestData)
    {
        // Ajouter des filtres personnalisés complexes
        if (isset($requestData['category_slug'])) {
            $query->whereHas('category', function ($q) use ($requestData) {
                $q->where('slug', $requestData['category_slug']);
            });
        }

        return $query;
    }
}
```

---

Exemples complets
-----------------

[](#exemples-complets)

### Exemple 1 : API de blog

[](#exemple-1--api-de-blog)

#### Modèle

[](#modèle)

```
namespace App\Models;

use Maravel\Models\ModelBase;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends ModelBase
{
    protected $fillable = ['title', 'content', 'user_id', 'published_at', 'status'];

    protected array $dateCasts = [
        'published_at' => 'd/m/Y H:i',
    ];

    protected array $enumCasts = [
        [
            'colum_name' => 'status',
            'choices' => [
                'draft' => 'Brouillon',
                'published' => 'Publié',
                'archived' => 'Archivé',
            ],
            'additional_column_name' => 'status_label',
        ],
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
```

#### Contrôleur

[](#contrôleur)

```
namespace App\Http\Controllers\API;

use Maravel\Http\Controllers\APIController;
use App\Models\Post;
use Illuminate\Support\Str;

class PostController extends APIController
{
    protected string $modelClass = Post::class;

    protected array $storeValidationArray = [
        'title' => 'required|string|max:255',
        'content' => 'required|string',
        'status' => 'in:draft,published,archived',
    ];

    protected array $updateValidationArray = [
        'title' => 'string|max:255',
        'content' => 'string',
        'status' => 'in:draft,published,archived',
    ];

    protected array $indexSearchFieldList = ['title', 'content'];
    protected array $indexWithArray = ['user'];

    protected function storeBeforeCreateFunction(array $data): array
    {
        $data['slug'] = Str::slug($data['title']);
        $data['user_id'] = auth()->id();

        if ($data['status'] === 'published' && !isset($data['published_at'])) {
            $data['published_at'] = now();
        }

        return $data;
    }

    protected function indexManualFilter($query, array $requestData)
    {
        // Seuls les posts publiés pour les non-admins
        if (!auth()->user()?->isAdmin()) {
            $query->where('status', 'published');
        }

        return $query;
    }
}
```

#### Routes

[](#routes)

```
Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('posts', PostController::class);
});
```

#### Utilisation

[](#utilisation)

```
# Lister les posts publiés avec leurs auteurs
GET /api/posts?with_user=true&in_status=published&order_by_desc=published_at

# Rechercher dans les posts
GET /api/posts?search=Laravel

# Créer un post
POST /api/posts
{
    "title": "Mon premier article",
    "content": "Contenu de l'article...",
    "status": "draft"
}
```

---

### Exemple 2 : E-commerce avec permissions

[](#exemple-2--e-commerce-avec-permissions)

#### Modèle Product

[](#modèle-product)

```
namespace App\Models;

use Maravel\Models\ModelBase;

class Product extends ModelBase
{
    protected $fillable = ['name', 'description', 'price', 'cost', 'stock', 'is_active'];

    protected array $moneyCasts = ['price', 'cost'];
    protected array $booleanCasts = ['is_active'];
}
```

#### Policy

[](#policy)

```
namespace App\Policies;

use Maravel\Policies\BasePolicy;
use App\Models\User;
use App\Models\Product;

class ProductPolicy extends BasePolicy
{
    protected string $subject = 'product';

    public function before(User $user, string $ability): ?bool
    {
        if ($user->profile === 'admin') {
            return true;
        }

        return null;
    }

    public function viewAny(User $user): bool
    {
        // Tout le monde peut voir les produits
        return true;
    }

    public function create(User $user): bool
    {
        return $this->checkCustomPermission($user, ['create'], $this->subject);
    }

    public function update(User $user, Product $product): bool
    {
        return $this->checkCustomPermission($user, ['update'], $this->subject);
    }

    public function updatePrice(User $user, Product $product): bool
    {
        // Seuls les admins et managers peuvent modifier les prix
        return in_array($user->profile, ['admin', 'manager']);
    }
}
```

#### Contrôleur

[](#contrôleur-1)

```
namespace App\Http\Controllers\API;

use Maravel\Http\Controllers\APIController;
use App\Models\Product;

class ProductController extends APIController
{
    protected string $modelClass = Product::class;

    protected array $storeValidationArray = [
        'name' => 'required|string|max:255',
        'description' => 'nullable|string',
        'price' => 'required|numeric|min:0',
        'cost' => 'required|numeric|min:0',
        'stock' => 'required|integer|min:0',
        'is_active' => 'boolean',
    ];

    protected array $updateValidationArray = [
        'name' => 'string|max:255',
        'description' => 'nullable|string',
        'price' => 'numeric|min:0',
        'cost' => 'numeric|min:0',
        'stock' => 'integer|min:0',
        'is_active' => 'boolean',
    ];

    protected array $indexSearchFieldList = ['name', 'description'];

    protected bool $indexCheckAbility = false; // Désactiver pour viewAny

    protected function updateManualValidationsFunction(array $data, $model): array
    {
        // Vérifier la permission pour modifier le prix
        if (isset($data['price'])) {
            if (!auth()->user()->can('updatePrice', $model)) {
                return ['price' => ['Vous n\'avez pas la permission de modifier le prix']];
            }
        }

        // Vérifier que le prix est supérieur au coût
        if (isset($data['price']) && $data['price'] < ($data['cost'] ?? $model->cost)) {
            return ['price' => ['Le prix doit être supérieur au coût']];
        }

        return [];
    }

    protected function storeAfterCommitFunction($model): void
    {
        // Créer l'historique de stock
        $model->stockHistory()->create([
            'quantity' => $model->stock,
            'type' => 'initial',
            'user_id' => auth()->id(),
        ]);
    }
}
```

#### Configuration des ability\_rules

[](#configuration-des-ability_rules)

```
// Pour un utilisateur "manager"
$user->ability_rules = [
    [
        'subject' => ['product'],
        'action' => ['read', 'create', 'update'],
    ],
];

// Pour un utilisateur "seller"
$user->ability_rules = [
    [
        'subject' => ['product'],
        'action' => ['read'],
    ],
];
```

---

Tests
-----

[](#tests)

La librairie inclut des tests PHPUnit pour assurer la qualité du code.

### Exécuter les tests

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

```
composer test
```

### Tests disponibles

[](#tests-disponibles)

- Tests du contrôleur API (CRUD complet)
- Tests des filtres (basiques, min/max, IN/NOT IN, etc.)
- Tests de la pagination
- Tests des relations
- Tests de validation
- Tests des permissions
- Tests des hooks

---

Changelog
---------

[](#changelog)

Consultez le fichier [CHANGELOG.md](CHANGELOG.md) pour voir l'historique complet des modifications.

---

Contribution
------------

[](#contribution)

Les contributions sont les bienvenues! Voici comment contribuer :

1. **Fork** le projet
2. Créez votre **branche de fonctionnalité** (`git checkout -b feature/AmazingFeature`)
3. **Committez** vos changements (`git commit -m 'Add some AmazingFeature'`)
4. **Push** vers la branche (`git push origin feature/AmazingFeature`)
5. Ouvrez une **Pull Request**

### Guidelines

[](#guidelines)

- Suivez les conventions de codage PSR-12
- Ajoutez des tests pour les nouvelles fonctionnalités
- Mettez à jour la documentation si nécessaire
- Assurez-vous que tous les tests passent

---

License
-------

[](#license)

Ce projet est sous licence MIT. Consultez le fichier [LICENSE](LICENSE) pour plus de détails.

Copyright (c) 2024 Charles GAMLIGO

---

Auteur
------

[](#auteur)

**Charles GAMLIGO** (Mawena)

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

---

Support
-------

[](#support)

- **Issues**: [GitHub Issues](https://github.com/mawena/maravel/issues)
- **Source**: [GitHub Repository](https://github.com/mawena/maravel)

---

Remerciements
-------------

[](#remerciements)

Merci à tous les contributeurs qui ont participé au développement de cette librairie.

---

**Maravel** - Accélérez votre développement d'API Laravel avec élégance et puissance.

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance73

Regular maintenance activity

Popularity13

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity64

Established project with proven stability

 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

Every ~2 days

Total

34

Last Release

154d ago

PHP version history (2 changes)v2.1.0PHP ^8.1

v2.2.3PHP ^8.1|^8.2|^8.3|^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/99b51ba88f5c5527792a32c01512e938dda54613af426aad841b104e7eaf707a?d=identicon)[mawena](/maintainers/mawena)

---

Top Contributors

[![mawena](https://avatars.githubusercontent.com/u/57989130?v=4)](https://github.com/mawena "mawena (46 commits)")

---

Tags

apilaravelpermissionscrudadvancedmodelscontrollertraitspolicies

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mawena-maravel/health.svg)

```
[![Health](https://phpackages.com/badges/mawena-maravel/health.svg)](https://phpackages.com/packages/mawena-maravel)
```

###  Alternatives

[santigarcor/laratrust

This package provides a flexible way to add Role-based Permissions to Laravel

2.3k5.4M43](/packages/santigarcor-laratrust)[silvanite/novatoolpermissions

Laravel Nova Permissions (Roles and Permission based Access Control (ACL))

100256.7k2](/packages/silvanite-novatoolpermissions)[pktharindu/nova-permissions

Laravel Nova Grouped Permissions (ACL)

136387.1k](/packages/pktharindu-nova-permissions)[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6712.1k2](/packages/hasinhayder-tyro)

PHPackages © 2026

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