nils-framework/nils-orm

ORM ActiveRecord léger avec champs typés, validation par règles, relations, Eager Loading, Identity Map et Serializer pour le framework NILS

Maintainers

Package info

gitlab.com/nils-framework/modules/nils-orm

Homepage

Issues

pkg:composer/nils-framework/nils-orm

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

v1.0 2026-06-09 17:30 UTC

This package is not auto-updated.

Last update: 2026-06-10 04:24:12 UTC


README

Latest Stable Version License PHP Version

Le composant nils-orm est la couche de mapping objet-relationnel (ORM) légère du framework PHP NILS. Construit au-dessus de nils-database, il fournit un pattern ActiveRecord sans attributs ni annotations : les modèles déclarent leur structure via une méthode definition() explicite, en parfaite cohérence avec la philosophie du framework.

Il embarque un système de champs typés, un moteur de validation par règles, des relations (One-to-Many, Many-to-One, Many-to-Many), l'Eager Loading anti N+1, une Identity Map, la pagination automatique et la génération de schéma SQL.

🚀 Fonctionnalités Clés

  • Modèles ActiveRecord déclaratifs : Structure définie par code (definition()), sans attributs PHP 8 ni configuration externe.
  • 13 types de champs typés : StringField, IntField, FloatField, BooleanField, DateField, DateTimeField, EmailField, PasswordField, TextField, JsonField, UuidField, ForeignKeyField... avec cast automatique PHP ↔ SQL.
  • Validation par règles (Fluent) : Unique, Exists, In, Min, Max, Regex — extensibles via RuleInterface.
  • Relations complètes : BelongsTo (Many-to-One), HasMany (One-to-Many) et BelongsToMany (Many-to-Many via table pivot), avec chargement paresseux (Lazy Loading) par accès magique.
  • Eager Loading (with()) : Résolution groupée des relations en une seule requête WHERE IN pour éliminer le problème des requêtes N+1.
  • Identity Map : Cache d'instances en mémoire garantissant qu'une ligne SQL correspond toujours au même objet PHP durant la requête.
  • Repository Pattern : Couche d'accès haut niveau — CRUD rapide, recherche textuelle, insertion de masse (Bulk Insert), transactions et pagination.
  • Serializer (inspiré de Django REST Framework) : Validation des données entrantes et extraction structurée des données sortantes pour vos APIs.
  • Schema Engine : Génération automatique des tables, index et contraintes de clés étrangères à partir des définitions de modèles.
  • Hooks de cycle de vie : beforeSave(), afterSave(), beforeDelete() pour greffer votre logique métier.
  • Timestamps automatiques : Gestion native de created_at / updated_at.

📦 Installation

Installez le module via Composer :

composer require nils-framework/nils-orm

Note : Ce package requiert nils-framework/nils-database (drivers, QueryBuilder, transactions) et s'intègre nativement au middleware d'exceptions de nils-core via ValidationException.

🛠️ Utilisation de Base

1. Définir un Modèle

use NilsOrm\Model;
use NilsOrm\Fields\StringField;
use NilsOrm\Fields\EmailField;
use NilsOrm\Fields\PasswordField;
use NilsOrm\Fields\BooleanField;
use NilsOrm\Rules\Unique;
use NilsOrm\Rules\Min;

class User extends Model
{
    protected static string $table = 'users';

    public static function definition(): array
    {
        return [
            'nom'      => new StringField(),
            'email'    => (new EmailField())->addRule(new Unique()),
            'password' => (new PasswordField())->addRule(new Min(8)),
            'actif'    => new BooleanField(),
        ];
    }
}

2. Opérations CRUD

// Création
$user = new User(['nom' => 'Traore', 'email' => 'traore@nils.dev']);
$user->save(); // Validation automatique avant insertion

// Lecture (avec Identity Map)
$user = User::find(1);

// Mise à jour
$user->nom = 'Traore N.';
$user->save();

// Suppression
$user->delete();

3. Déclarer des Relations

use NilsOrm\Relations\HasMany;
use NilsOrm\Relations\BelongsTo;
use NilsOrm\Relations\BelongsToMany;

class Article extends Model
{
    public static function relations(): array
    {
        return [
            'auteur'     => new BelongsTo(User::class, 'user_id'),
            'categories' => new BelongsToMany(Category::class, 'article_category', 'article_id', 'category_id'),
        ];
    }
}

// Accès paresseux (Lazy Loading)
$article = Article::find(1);
echo $article->auteur->nom;        // Charge le parent à la demande
$categories = $article->categories; // Charge via la table pivot

4. Repository, Recherche et Pagination

use NilsOrm\Repository;

$repo = new Repository(Article::class);

// Eager Loading : 2 requêtes au total, quel que soit le nombre d'articles
$pagination = $repo->with(['auteur', 'categories'])->paginate(page: 1, perPage: 15);

// Recherche textuelle filtrée
$qb = $repo->search('framework', ['titre', 'contenu'], ['actif' => 1]);
$resultats = $repo->paginate($qb, page: 2);

// Réponse API standardisée
return $pagination->toArray();
// ['items' => [...], 'meta' => ['total' => ..., 'current_page' => ..., 'per_page' => ..., 'last_page' => ...]]

5. Transactions et Insertion de Masse

$repo->transaction(function () use ($repo) {
    $repo->create(['titre' => 'Article 1']);
    $repo->createMany([
        ['titre' => 'Article 2', 'user_id' => 1],
        ['titre' => 'Article 3', 'user_id' => 1],
    ]);
}); // Rollback automatique en cas d'exception

6. Valider les Données Entrantes (Serializer)

use NilsOrm\Serializer;

class UserSerializer extends Serializer
{
    public function fields(): array
    {
        return (User::definition()); // Réutilisation directe des champs du modèle
    }
}

// Dans un contrôleur NILS
$serializer = new UserSerializer(data: $body);
$donnees = $serializer->validateOrFail(); // Lève ValidationException → réponse 400 JSON structurée

7. Générer le Schéma SQL

use NilsOrm\SchemaEngine;

SchemaEngine::createTableFromModel(User::class);
SchemaEngine::createTableFromModel(Article::class);
// Tables, index, contraintes UNIQUE et clés étrangères créés automatiquement

📦 Architecture du Dépôt

src/
├── Exceptions/
│   └── ValidationException.php   # Exception 400 structurée par champ
└── NilsOrm/
    ├── Fields/                   # 13 types de champs typés (cast + SQL)
    ├── Relations/                # BelongsTo, HasMany, BelongsToMany
    ├── Rules/                    # Unique, Exists, In, Min, Max, Regex
    ├── Model.php                 # ActiveRecord (CRUD, hooks, lazy loading)
    ├── Repository.php            # Accès haut niveau (Eager Loading, transactions)
    ├── IdentityMap.php           # Cache d'instances en mémoire
    ├── Pagination.php            # Résultats paginés prêts pour JSON
    ├── SchemaEngine.php          # Génération DDL depuis les modèles
    └── Serializer.php            # Validation entrante / extraction sortante

⚙️ Cache et Cohérence

L'Identity Map garantit que deux appels à User::find(1) au sein d'une même requête HTTP retournent la même instance PHP, sans requête SQL redondante. Le registre est automatiquement synchronisé lors des opérations save() et peut être vidé manuellement :

use NilsOrm\IdentityMap;

IdentityMap::clear(); // Réinitialisation complète du registre

📄 Licence

Ce projet est distribué sous licence MIT. Développé avec passion par Traore.