PHPackages                             bdvvn/query-builder - 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. bdvvn/query-builder

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

bdvvn/query-builder
===================

Query builder SQL fluide et immuable, multi-dialecte, sans dépendance d'exécution

00PHP

Since Jun 5Pushed 1mo agoCompare

[ Source](https://github.com/bdvvn/query-builder)[ Packagist](https://packagist.org/packages/bdvvn/query-builder)[ RSS](/packages/bdvvn-query-builder/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

bdvvn/query-builder
===================

[](#bdvvnquery-builder)

Query builder SQL **fluide, immuable et sécurisé**, multi-dialecte, **sans dépendance d'exécution**.

La bibliothèque a un seul rôle : produire des requêtes SQL **paramétrées** (`sql` + `bindings`) de façon expressive, sans ORM ni magie, et **sans jamais exposer de surface d'injection SQL** — ni sur les valeurs (toujours bindées), ni sur les identifiants (toujours validés et quotés).

Elle n'exécute rien : tu récupères un `CompiledQuery` et tu l'exécutes avec **ta propre couche d'accès aux données** (PDO brut, Doctrine DBAL, un mock en test, etc.).

```
use Bdvvn\QueryBuilder\Adapter\MySqlAdapter;
use Bdvvn\QueryBuilder\QueryFactory;

$qf = new QueryFactory(new MySqlAdapter());

$query = $qf->table('articles', 'a')
    ->select('a.id', 'a.titre', 'auteurs.nom')
    ->join('auteurs', 'auteurs.id', '=', 'a.auteur_id')
    ->where('a.publie', '=', true)
    ->whereNotNull('a.publie_le')
    ->orderBy('a.publie_le', 'DESC')
    ->limit(10)
    ->compileSelect();

// $query->sql      → "SELECT `a`.`id`, ... FROM `articles` AS `a` ... LIMIT 10"
// $query->bindings → [true]

$stmt = $pdo->prepare($query->sql);   // ta couche d'exécution
$stmt->execute($query->bindings);
$articles = $stmt->fetchAll();
```

---

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

[](#installation)

```
composer require bdvvn/query-builder
```

Aucune extension requise (PHP `^8.5`). En particulier, **aucune dépendance à PDO**.

---

Concepts
--------

[](#concepts)

### `QueryFactory` — choisir le dialecte une fois

[](#queryfactory--choisir-le-dialecte-une-fois)

Le dialecte (quoting des identifiants, syntaxe `LIMIT`/`OFFSET`) est porté par un `SqlAdapter`. On le configure une fois dans la fabrique :

```
use Bdvvn\QueryBuilder\Adapter\{MySqlAdapter, PostgreSqlAdapter, SqliteAdapter};
use Bdvvn\QueryBuilder\QueryFactory;

$qf = new QueryFactory(new PostgreSqlAdapter());
$qb = $qf->table('articles');           // un QueryBuilder
```

### `QueryBuilder` — construire (immuable)

[](#querybuilder--construire-immuable)

Toutes les clauses sont disponibles en API fluide : `select`/`addSelect`/`selectRaw`/`distinct`, `join`/`leftJoin`/`rightJoin`/`crossJoin`/`joinRaw`, `where`/`orWhere` et leurs variantes (`whereNull`, `whereIn`, `whereBetween`, `whereColumn`, `whereRaw`…), `groupBy`, `having` avec la **même symétrie** que `where` (`havingNull`, `havingIn`, `havingBetween`, `havingRaw`…), `orderBy`, `limit`, `offset`, ainsi que `union`/`unionAll`.

```
// DISTINCT + comparaison de colonnes
$qf->table('stock')->distinct()->select('ref')->whereColumn('quantite', 'table('articles')->select('id')->where('publie', '=', true);
$qf->table('brouillons')->select('id')->where('auteur_id', '=', 5)
   ->union($publies)->orderByRaw('id ASC')->limit(10);
```

L'objet est **immuable** : chaque méthode renvoie une nouvelle instance, ce qui rend les requêtes de base réutilisables sans effet de bord.

```
$base    = $qf->table('articles')->where('publie', '=', true);
$recents = $base->orderBy('publie_le', 'DESC')->limit(5);
// $base n'a pas été modifié
```

### `CompiledQuery` — le résultat à exécuter

[](#compiledquery--le-résultat-à-exécuter)

Les terminales renvoient un `CompiledQuery` immuable (`->sql`, `->bindings`) :

MéthodeProduit`compileSelect(?int $forceLimit = null)``SELECT …``compileCount()``SELECT COUNT(*) …` (sous-requête si `GROUP BY`/`HAVING`/`DISTINCT`)`compileExists()``SELECT 1 … LIMIT 1``compileInsert(array $data)``INSERT INTO …` (une ligne)`compileInsertMany(array $rows)``INSERT INTO … VALUES (…), (…)` (multi-lignes, colonnes identiques)`compileUpdate(array $data, bool $allowEmptyWhere = false)``UPDATE …``compileDelete(bool $allowEmptyWhere = false)``DELETE …`Introspection sans exécution : `toSql(?int $forceLimit = null)` et `getBindings()`.

```
$q = $qf->table('articles')->where('id', '=', 7)->compileUpdate(['titre' => 'X']);
// $q->sql      → 'UPDATE "articles" SET "titre" = ? WHERE "id" = ?'
// $q->bindings → ['X', 7]
```

Garde-fous repris du builder d'origine : `compileUpdate()`/`compileDelete()` **exigent un `WHERE`**(sauf `allowEmptyWhere: true`) et refusent les clauses qu'un DML standard ne supporte pas universellement (JOIN, GROUP BY, alias…).

---

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

[](#sécurité)

- **Valeurs** : jamais interpolées, toujours rendues sous forme de `?` + binding.
- **Identifiants** (tables, colonnes, alias) : validés par `IdentifierValidator` (regex stricte, longueur bornée) puis quotés par le dialecte. Un `select($_GET['col'])` non conforme lève une exception.
- **Opérateurs** : restreints à une whitelist (`SqlOperator`).
- **Fragments `*Raw()`** (`selectRaw`, `whereRaw`, `joinRaw`, `groupByRaw`, `orderByRaw`, `havingRaw`) : insérés tels quels dans le SQL — c'est la **seule** porte d'injection. N'y mets jamais d'entrée utilisateur concaténée ; passe les valeurs dynamiques en `?` via l'argument `$bindings`.
- **`LIKE`** : les méta-caractères `%` et `_` présents dans la valeur ne sont **pas** échappés (comportement standard). Si la valeur vient de l'utilisateur, échappe-la côté appelant.

C'est l'**exécutant** (toi) qui reste responsable d'utiliser une requête préparée avec les `bindings`fournis — ne jamais réinjecter `->sql` en concaténant des valeurs.

---

Exécution : à toi de jouer
--------------------------

[](#exécution--à-toi-de-jouer)

La bibliothèque s'arrête à `CompiledQuery`. Côté exécution, deux options :

1. **Ta propre couche** (PDO, DBAL, …) comme dans les exemples ci-dessus.
2. **[bdvvn/database](../database)** : surcouche PDO multi-driver qui ajoute une `Connection`, les transactions et un `ExecutingQueryBuilder` exposant directement `find()`, `findAll()`, `insert()`, `update()`, `delete()` — pour qui veut le confort sans assembler l'exécution soi-même.

---

Dialectes fournis
-----------------

[](#dialectes-fournis)

`MySqlAdapter` (backticks), `PostgreSqlAdapter` / `SqliteAdapter` (guillemets doubles). Pour un autre SGBD, étendre `AbstractSqlAdapter` (définir le caractère de quoting et, au besoin, la syntaxe `OFFSET` sans `LIMIT`) et le passer à `QueryFactory`.

---

Qualité du code
---------------

[](#qualité-du-code)

```
composer qa     # phpstan (niveau 10 + strict-rules), phpmd, php-cs-fixer, phpunit
```

Documentation de référence par classe dans [`doc/`](doc/).

###  Health Score

19

—

LowBetter than 9% of packages

Maintenance59

Moderate activity, may be stable

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/ced47a7ec09db3861bb82581bd89231486504042bf3aa4df11a0ffa48fb7b21b?d=identicon)[bdvvn](/maintainers/bdvvn)

---

Top Contributors

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

### Embed Badge

![Health badge](/badges/bdvvn-query-builder/health.svg)

```
[![Health](https://phpackages.com/badges/bdvvn-query-builder/health.svg)](https://phpackages.com/packages/bdvvn-query-builder)
```

###  Alternatives

[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k117.2M118](/packages/jdorn-sql-formatter)[propel/propel1

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

8351.6M87](/packages/propel-propel1)[jfelder/oracledb

Oracle DB driver for Laravel

11518.4k](/packages/jfelder-oracledb)

PHPackages © 2026

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