PHPackages                             velt/database - 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. [Database &amp; ORM](/categories/database)
4. /
5. velt/database

ActiveLibrary[Database &amp; ORM](/categories/database)

velt/database
=============

Velt Database PDO module

v0.1.0(yesterday)04↑2900%22MITPHPPHP ^8.1

Since Jun 18Pushed yesterdayCompare

[ Source](https://github.com/Velt-PHP/velt-database)[ Packagist](https://packagist.org/packages/velt/database)[ RSS](/packages/velt-database/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (2)Versions (2)Used By (2)

Velt Database - Module PDO Complet
==================================

[](#velt-database---module-pdo-complet)

Mise a jour Module 3 Data ORM
-----------------------------

[](#mise-a-jour-module-3-data-orm)

Le package contient maintenant les fondations database suivantes, sans modifier le repo `veltphp-cli`.

### Query Builder

[](#query-builder)

```
use Velt\Database\DB;

$user = DB::table('users')->where('email', $email)->first();
$users = DB::table('users')->select('id', 'name')->orderBy('id')->limit(10)->get();
DB::table('users')->insert(['name' => 'Ada', 'email' => 'ada@example.com']);
DB::table('users')->where('id', 1)->update(['name' => 'Ada Lovelace']);
DB::table('users')->where('id', 1)->delete();
```

Toutes les valeurs dynamiques passent par des requetes preparees. Les noms de tables et colonnes sont valides comme identifiers SQL avant compilation.

### Schema Builder et migrations

[](#schema-builder-et-migrations)

```
use Velt\Database\Schema\Blueprint;
use Velt\Database\Schema\Schema;

Schema::create('users', function (Blueprint $table): void {
    $table->id();
    $table->string('name');
    $table->integer('age');
    $table->timestamps();
});

Schema::drop('users');
```

Le runner de migrations est disponible cote runtime :

```
use Velt\Database\Migrations\Migrator;

$migrator = new Migrator(__DIR__ . '/database/migrations');
$migrator->migrate();
$migrator->rollback();
```

Les commandes `php bin/velt migrate`, `migrate:rollback`, `make:migration`, `make:seeder` et `db:seed` doivent etre ajoutees dans `veltphp-cli`. Voir `issues/06-cli-database-commands.md`.

### Seeders et factories

[](#seeders-et-factories)

```
use Velt\Database\Seeders\Seeder;

final class UserSeeder extends Seeder
{
    public function run(): void
    {
        DB::table('users')->insert(['name' => 'Ada', 'email' => 'ada@example.com']);
    }
}
```

```
use Velt\Database\Factories\Factory;

final class UserFactory extends Factory
{
    public function definition(): array
    {
        return ['name' => 'Ada', 'email' => 'ada@example.com'];
    }

    protected function table(): string
    {
        return 'users';
    }
}
```

### Cache de resultats

[](#cache-de-resultats)

```
use Velt\Database\Cache\FileDatabaseCache;

DB::setCache(new FileDatabaseCache(__DIR__ . '/storage/database-cache'));

$users = DB::table('users')->where('active', 1)->remember(60)->get();
DB::cache()->flush();
```

En environnement `testing`, `DatabaseServiceProvider` utilise un cache nul par defaut.

Vue d'ensemble
--------------

[](#vue-densemble)

Ce module fournit une couche d'abstraction de base de données pour le framework Velt, implémentant les 5 premières étapes d'un système de gestion de base de données robuste et sécurisé.

**Statut:** Complet - 5/5 issues implémentées, 19 tests passants

---

Objectifs et raisons
--------------------

[](#objectifs-et-raisons)

### Pourquoi ce module?

[](#pourquoi-ce-module)

Le framework Velt nécessite une couche d'accès aux données **centralisée, sécurisée et extensible**:

- **Sécurité:** Prévenir les injections SQL via requêtes préparées obligatoires
- **Maintenabilité:** Isoler la logique de base de données du reste de l'application
- **Flexibilité:** Supporter plusieurs drivers (SQLite, MySQL, PostgreSQL)
- **Performance:** Mise en cache des connexions, pas de reconnexions inutiles
- **Testabilité:** Interfaces mockables et fakes pour les tests

---

Architecture générale
---------------------

[](#architecture-générale)

```
┌─────────────────────────────────────────────────────────┐
│  Velt Application Kernel                                │
└────────────────┬────────────────────────────────────────┘
                 │ registerProvider
                 ▼
┌─────────────────────────────────────────────────────────┐
│  DatabaseServiceProvider (Enregistrement DI)            │
│  - Crée singleton DatabaseManager                       │
└────────────────┬────────────────────────────────────────┘
                 │ registre comme singleton
                 ▼
┌─────────────────────────────────────────────────────────┐
│  DatabaseManager                                        │
│  - Gère pool de connexions nommées                      │
│  - Lecture config, création PDO via Factory            │
└────────────────┬────────────────────────────────────────┘
                 │ utilise
                 ▼
┌──────────────────────┬──────────────────────┐
│  ConnectionFactory   │  DB (Facade)         │
│  - Crée DSN          │  - static interface  │
│  - Prépare PDO       │  - select/first etc. │
└──────────────────────┴──────────────────────┘
                 │ utilisé par
                 ▼
┌─────────────────────────────────────────────────────────┐
│  Model (Classe de base)                                 │
│  - find(), all(), create()                              │
│  - Accès simplifié aux données                          │
└─────────────────────────────────────────────────────────┘

```

---

Composants implémentés
----------------------

[](#composants-implémentés)

### 1. **ConnectionFactory** (`src/ConnectionFactory.php`)

[](#1-connectionfactory-srcconnectionfactoryphp)

**Responsabilité:** Construire les chaînes de connexion (DSN) et créer des instances PDO.

**Pourquoi?**

- Centraliser la logique de création PDO
- Supporter plusieurs drivers avec leurs syntaxes différentes
- Valider et documenter les paramètres requis pour chaque driver

**Drivers supportés:**

```
// SQLite (fichier ou mémoire)
'sqlite' => [
    'driver' => 'sqlite',
    'database' => ':memory:'  // ou '/path/to/db.sqlite'
]

// MySQL
'mysql' => [
    'driver' => 'mysql',
    'host' => 'localhost',
    'port' => 3306,
    'database' => 'velt',
    'charset' => 'utf8mb4'
]

// PostgreSQL
'pgsql' => [
    'driver' => 'pgsql',
    'host' => 'localhost',
    'port' => 5432,
    'database' => 'velt'
]
```

**DSN générés:**

```
sqlite:  sqlite::memory: ou sqlite:/path/to/db.sqlite
mysql:   mysql:host=localhost;port=3306;dbname=velt;charset=utf8mb4
pgsql:   pgsql:host=localhost;port=5432;dbname=velt

```

**Méthodes clés:**

```
public function create(array $connection): PDO
// Retourne une instance PDO configurée

private function buildDsn(array $connection): string
// Construit la chaîne de connexion appropriée

private function buildSqliteDsn(array $connection): string
private function buildMysqlDsn(array $connection): string
private function buildPgsqlDsn(array $connection): string
// Builders spécifiques par driver
```

---

### 2. **DatabaseManager** (`src/DatabaseManager.php`)

[](#2-databasemanager-srcdatabasemanagerphp)

**Responsabilité:** Gérer un pool de connexions nommées avec cache et initialisation lazy.

**Pourquoi?**

- Éviter de créer plusieurs PDO pour la même connexion
- Supporter plusieurs bases de données simultanément (ex: tenant separation)
- Résoudre la connexion par défaut automatiquement
- Valider la configuration au moment de l'accès, pas au démarrage

**Fonctionnement:**

```
// Première fois: création et cache
$pdo = $manager->connection('default');  // crée et cache

// Fois suivante: retour du cache
$pdo = $manager->connection('default');  // retour cache, pas de reconnexion
```

**Configuration attendue:**

```
// config/database.php
return [
    'default' => 'sqlite',  // connexion par défaut
    'connections' => [
        'sqlite' => [
            'driver' => 'sqlite',
            'database' => ':memory:'
        ],
        // autres connexions...
    ]
];
```

**Méthodes clés:**

```
public function connection(?string $name = null): PDO
// Obtenir une connexion (crée ou retourne du cache)

private function defaultConnectionName(): string
// Résoudre le nom de connexion par défaut depuis config
```

---

### 3. **DB** (`src/DB.php`) - Facade statique

[](#3-db-srcdbphp---facade-statique)

**Responsabilité:** Fournir une interface statique simple pour exécuter des requêtes.

**Pourquoi?**

- Accès au DatabaseManager depuis n'importe où sans DI
- Enforce obligatoire des requêtes préparées (pas de concat string)
- Méthodes nommées intuitives (select, first, statement)
- Support natif des transactions

**Pattern utilisé:** Facade statique avec délégation

**Requêtes préparées obligatoires:**

```
//  AUTORISÉ - Requête préparée
DB::select('SELECT * FROM users WHERE id = ?', [1]);
DB::select('SELECT * FROM users WHERE email = ?', [$email]);

//  INTERDIT - Interprétation SQL interdite
// (Les placeholders ? sont obligatoires)
```

**Méthodes disponibles:**

```
// Retourner tous les résultats
public static function select(string $sql, array $bindings = []): array

// Retourner le premier résultat ou null
public static function first(string $sql, array $bindings = []): ?array

// Exécuter INSERT/UPDATE/DELETE, retourner le nombre de lignes affectées
public static function statement(string $sql, array $bindings = []): int

// Transaction: commit si succès, rollback si exception
public static function transaction(callable $callback): mixed
```

**Exemples:**

```
// SELECT
$users = DB::select('SELECT * FROM users WHERE age > ?', [18]);

// FIRST
$user = DB::first('SELECT * FROM users WHERE email = ?', ['test@example.com']);

// INSERT/UPDATE/DELETE
$affected = DB::statement(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    ['John', 'john@example.com']
);

// TRANSACTION
DB::transaction(function() {
    DB::statement('INSERT INTO logs (action) VALUES (?)', ['action1']);
    DB::statement('INSERT INTO logs (action) VALUES (?)', ['action2']);
    // Si une exception: rollback automatique
});
```

---

### 4. **Model** (`src/Model.php`) - Classe de base MVP

[](#4-model-srcmodelphp---classe-de-base-mvp)

**Responsabilité:** Fournir des méthodes CRUD simples pour accéder aux données.

**Pourquoi MVP (Minimum Viable Product)?**

- Débuter simple sans relations, dirty checking, ou mass assignment
- Laisser place pour extensions futures
- Couvrir les opérations basiques (trouver, lister, créer)

**Utilisation:**

```
// Définir un modèle
class User extends Model
{
    protected string $table = 'users';
}

// Utiliser le modèle
$user = User::find(1);           // SELECT * FROM users WHERE id = 1
$users = User::all();             // SELECT * FROM users
$id = User::create([              // INSERT INTO users (...)
    'name' => 'John',
    'email' => 'john@example.com'
]);
```

**Méthodes disponibles:**

```
// Retrouver par ID (retourne array ou null)
public static function find(int|string $id): ?array

// Récupérer tous les enregistrements
public static function all(): array

// Créer un nouvel enregistrement (retourne l'ID)
public static function create(array $attributes): int

// (Interne) Nom de la table
protected static function tableName(): string
```

**Limitations actuelles (MVP):**

- Pas de relations (belongsTo, hasMany, etc.)
- Pas de dirty tracking (modification avant save)
- Pas de mass assignment protection
- Pas de validation built-in
- Pas de scopes ou query builder fluent

Ces fonctionnalités seront ajoutées dans les phases suivantes.

---

### 5. **DatabaseServiceProvider** (`src/DatabaseServiceProvider.php`)

[](#5-databaseserviceprovider-srcdatabaseserviceproviderphp)

**Responsabilité:** Enregistrer DatabaseManager dans le conteneur DI avec initialisation lazy.

**Pourquoi un Service Provider?**

- Pattern standard pour organiser les enregistrements DI
- Initialisation lazy: DatabaseManager créé seulement si utilisé
- Accès au ConfigRepository depuis le conteneur
- Préparé pour intégration avec kernel Velt

**Enregistrement:**

```
public function register(ContainerInterface $container): void
{
    // Enregistrer comme singleton
    $container->singleton(DatabaseManager::class, function() use ($container) {
        $config = $container->get(ConfigRepositoryInterface::class);
        return new DatabaseManager($config);
    });
}
```

**Utilisation dans le kernel:**

```
// Dans le kernel ou bootstrap
$serviceProvider = new DatabaseServiceProvider();
$serviceProvider->register($container);

// Le DatabaseManager n'est créé que lors du premier accès
$manager = $container->get(DatabaseManager::class);
```

---

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

[](#configuration)

### Structure attendue

[](#structure-attendue)

```
// config/database.php
return [
    // Connexion par défaut utilisée par DB::
    'default' => env('DB_CONNECTION', 'sqlite'),

    'connections' => [
        'sqlite' => [
            'driver' => 'sqlite',
            'database' => env('DB_DATABASE', ':memory:'),
        ],

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', 'localhost'),
            'port' => env('DB_PORT', 3306),
            'database' => env('DB_DATABASE', 'velt'),
            'charset' => 'utf8mb4',
        ],

        'pgsql' => [
            'driver' => 'pgsql',
            'host' => env('DB_HOST', 'localhost'),
            'port' => env('DB_PORT', 5432),
            'database' => env('DB_DATABASE', 'velt'),
        ],
    ],
];
```

---

Utilisation complète
--------------------

[](#utilisation-complète)

### Configuration du service provider

[](#configuration-du-service-provider)

```
// Dans le kernel
use Velt\Database\DatabaseServiceProvider;

class Kernel
{
    protected array $serviceProviders = [
        // ... autres providers
        DatabaseServiceProvider::class,
    ];
}
```

### Utiliser DB (Facade)

[](#utiliser-db-facade)

```
use Velt\Database\DB;

// Requêtes SELECT
$users = DB::select('SELECT * FROM users WHERE active = ?', [1]);
$user = DB::first('SELECT * FROM users WHERE id = ?', [1]);

// Modification de données
$affected = DB::statement(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    ['Alice', 'alice@example.com']
);

// Transactions
DB::transaction(function() {
    DB::statement('UPDATE users SET balance = balance - ? WHERE id = ?', [100, 1]);
    DB::statement('UPDATE users SET balance = balance + ? WHERE id = ?', [100, 2]);
    // Les deux exécutées, ou rien si erreur
});
```

### Utiliser les Models

[](#utiliser-les-models)

```
use Velt\Database\Model;

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

// Créer
$id = User::create([
    'name' => 'Bob',
    'email' => 'bob@example.com'
]);

// Lire
$user = User::find(1);
$users = User::all();

//  UPDATE et DELETE ne sont pas implémentés en MVP
// Utiliser DB::statement() pour ces opérations
```

---

Tests
-----

[](#tests)

### Exécuter les tests

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

```
composer test
```

**Résultat attendu:**

```
PHPUnit 10.5.63 by Sebastian Bergmann and contributors.

...................                                      19 / 19 (100%)

Time: 00:00.027, Memory: 8.00 MB

OK (19 tests, 39 assertions)

```

### Structure des tests

[](#structure-des-tests)

```
tests/
├── Fakes/
│   ├── ArrayConfigRepository.php    # Fake ConfigRepository
│   └── ArrayContainer.php           # Fake ContainerInterface
├── ConnectionFactoryTest.php        # 5 tests
├── DatabaseManagerTest.php          # 4 tests
├── DBTest.php                       # 5 tests
├── ModelTest.php                    # 3 tests
└── DatabaseServiceProviderTest.php  # 2 tests

```

### Couverture de tests

[](#couverture-de-tests)

ComposantTestsCas couvertsConnectionFactory5DSN SQLite/MySQL/PostgreSQL, drivers inconnusDatabaseManager4Cache, connexion par défaut, validationDB5select, first, statement, transactionsModel3find, all, createServiceProvider2Enregistrement, lazy resolution**Total****19****39 assertions**---

Sécurité
--------

[](#sécurité)

### Requêtes préparées obligatoires

[](#requêtes-préparées-obligatoires)

**Tous les accès à la base utilisent des prepared statements:**

```
// Paramètres bindés de manière sécurisée
DB::select('SELECT * FROM users WHERE email = ?', [$userInput]);
DB::select('SELECT * FROM users WHERE email = ? AND role = ?', [$email, $role]);
```

**Pas de concaténation string:**

```
// JAMAIS FAIRE CELA - INJECTION SQL!
$sql = "SELECT * FROM users WHERE email = '$userInput'";
```

### Gestion des erreurs

[](#gestion-des-erreurs)

```
try {
    $pdo = $factory->create(['driver' => 'invalid']);
} catch (UnknownDatabaseDriverException $e) {
    // Message d'erreur explicite
}
```

---

Design Patterns utilisés
------------------------

[](#design-patterns-utilisés)

### 1. **Factory Pattern**

[](#1-factory-pattern)

```
// ConnectionFactory crée les instances PDO
$factory = new ConnectionFactory();
$pdo = $factory->create($config);
```

Centralise la création complexe

### 2. **Service Provider Pattern**

[](#2-service-provider-pattern)

```
// Enregistrer les services au démarrage
$provider = new DatabaseServiceProvider();
$provider->register($container);
```

Organise l'initialisation des services

### 3. **Facade Pattern**

[](#3-facade-pattern)

```
// Interface simple et statique
DB::select(...);
DB::transaction(...);
```

Simplifie l'utilisation depuis n'importe où

### 4. **Singleton Pattern**

[](#4-singleton-pattern)

```
// DatabaseManager créé une seule fois
$container->singleton(DatabaseManager::class, ...);
```

Évite les connexions multiples

### 5. **Dependency Injection**

[](#5-dependency-injection)

```
// Les dépendances sont injectées, pas créées localement
public function __construct(
    private ConfigRepositoryInterface $config,
) {}
```

Testabilité et flexibilité

### 6. **Repository Pattern**

[](#6-repository-pattern)

```
// Abstraction de la source de config
interface ConfigRepositoryInterface {
    public function get(string $key, mixed $default = null): mixed;
}
```

Découple de l'implémentation

---

Avantages de cette implémentation
---------------------------------

[](#avantages-de-cette-implémentation)

AspectBénéfice**Sécurité**Prepared statements obligatoires, pas d'injection SQL**Performance**Cache de connexions, pas de PDO redondants**Maintenabilité**Code séparé et organisé par responsabilité**Flexibilité**Support de 3 drivers, extensible facilement**Testabilité**Interfaces mockables, 19 tests complets**Usabilité**Facade simple (DB::select), Models intuitifs**Scalabilité**Support de connexions multiples nommées---

📋 Issues implémentées
---------------------

[](#-issues-implémentées)

✅ **Issue 01:** DatabaseManager avec ConnectionFactory

- DSN builders pour SQLite, MySQL, PostgreSQL
- Gestion des erreurs et validation

✅ **Issue 02:** Query helper sécurisé

- Facade DB statique
- Prepared statements obligatoires
- Transactions avec commit/rollback

✅ **Issue 03:** BaseModel MVP

- Méthodes find(), all(), create()
- Configuration par table
- Prêt pour extensions

✅ **Issue 04:** Intégration configuration

- Lecture config en dot notation (database.connections.default)
- Support des drivers multiples
- Validation explicite

✅ **Issue 05:** DatabaseServiceProvider

- Enregistrement singleton
- Initialisation lazy
- Prêt pour kernel Velt

---

🚀 Prochaines étapes possibles
-----------------------------

[](#-prochaines-étapes-possibles)

### Phase 2 (Proposé)

[](#phase-2-proposé)

- Query Builder fluent (select()-&gt;where()-&gt;get())
- Relations (belongsTo, hasMany, hasManyThrough)
- Scopes et query macros
- Validation de modèle built-in
- Soft deletes

### Phase 3 (Proposé)

[](#phase-3-proposé)

- Migrations système
- Seeders
- Database transactions au niveau modèle
- Eager loading et lazy loading

### Phase 4 (Proposé)

[](#phase-4-proposé)

- Query caching
- Read replicas
- Database profiling et logging
- Support MongoDB/Redis

---

📝 Notes de développement
------------------------

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

### Structure de répertoires

[](#structure-de-répertoires)

```
src/
├── ConnectionFactory.php                  # Crée PDO
├── DatabaseManager.php                    # Pool de connexions
├── DB.php                                 # Facade statique
├── Model.php                              # Classe de base
├── DatabaseServiceProvider.php            # Enregistrement DI
└── Contracts/
    ├── ConfigRepositoryInterface.php      # Configuration
    └── ContainerInterface.php             # DI Container

tests/
├── Fakes/
│   ├── ArrayConfigRepository.php          # Test config
│   └── ArrayContainer.php                 # Test DI
├── ConnectionFactoryTest.php
├── DatabaseManagerTest.php
├── DBTest.php
├── ModelTest.php
└── DatabaseServiceProviderTest.php

```

### Conventions de code

[](#conventions-de-code)

- **Strict types:** `declare(strict_types=1)` sur tous les fichiers
- **Namespaces:** `Velt\Database`
- **PSR-4:** Autoloading standard
- **Type hints:** Tous les paramètres et retours typés
- **Commentaires:** En français, explicatifs

### Erreurs personnalisées

[](#erreurs-personnalisées)

```
// Base
DatabaseConfigurationException extends RuntimeException

// Spécifiques
UnknownDatabaseDriverException extends DatabaseConfigurationException
```

---

📞 Support
---------

[](#-support)

Pour des questions ou problèmes:

1. Vérifier les tests dans `tests/`
2. Consulter les commentaires en français dans le code
3. Référencer cette documentation

---

**Statut du module:** ✅ Prêt pour production **Couverture de tests:** 100% des chemins critiques **Documentation:** Complète en français **Dernière mise à jour:** Mai 2026

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance100

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 50% 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://avatars.githubusercontent.com/u/233258904?v=4)[Kaluba sierra](/maintainers/skylore300-hash)[@skylore300-hash](https://github.com/skylore300-hash)

---

Top Contributors

[![Athena-Evan01](https://avatars.githubusercontent.com/u/215157142?v=4)](https://github.com/Athena-Evan01 "Athena-Evan01 (6 commits)")[![KeranTyrinthe](https://avatars.githubusercontent.com/u/177726053?v=4)](https://github.com/KeranTyrinthe "KeranTyrinthe (3 commits)")[![skylore300-hash](https://avatars.githubusercontent.com/u/233258904?v=4)](https://github.com/skylore300-hash "skylore300-hash (3 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/velt-database/health.svg)

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

###  Alternatives

[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k116.5M113](/packages/jdorn-sql-formatter)[propel/propel1

Propel is an open-source Object-Relational Mapping (ORM) for PHP5.

8351.6M87](/packages/propel-propel1)[yemenopensource/filament-excel

This package useful for importing excel files into models.

194.2k](/packages/yemenopensource-filament-excel)

PHPackages © 2026

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