-
Notifications
You must be signed in to change notification settings - Fork 0
FAQ
Common questions about InitORM QueryBuilder.
No. It only builds SQL strings and a parameter bag. You hand both to PDO yourself. The builder never opens a connection.
$stmt = $pdo->prepare($qb->generateSelectQuery());
$stmt->execute($qb->getParameter()->all());Different goals:
- Doctrine DBAL — full database-abstraction layer with schema introspection, migrations, type coercion.
- Laravel query builder — tightly coupled to the Eloquent / Illuminate ecosystem.
-
InitORM QueryBuilder — small, framework-agnostic, zero runtime
dependencies. Pairs naturally with
initorm/dbalfor connection management or with raw PDO when you don't need a connection layer.
If you need schema migrations and a connection layer, pick a heavier toolkit. If you want to drop a small builder into an existing PDO setup without inheriting a framework, this is the right tool.
Yes. 324 unit tests, 97 % line coverage, PHPStan level 6, PSR-12,
CI on PHP 8.1–8.4. The 2.0.0 release also fixed a documented
SQL-injection vector (FIND_IN_SET, B28 in the CHANGELOG) and added a
dedicated security regression suite.
PHP 8.1+. The CI matrix covers 8.1 / 8.2 / 8.3 / 8.4.
Just ext-pdo — and that's only needed by your application code at
execution time. The builder itself doesn't open a connection. Dev
dependencies are PHPUnit, PHP_CodeSniffer and PHPStan.
No. You pick the dialect driver (= identifier-quoting strategy) when you construct the builder:
new QueryBuilder('mysql'); // backticks
new QueryBuilder('pgsql'); // double-quotes
new QueryBuilder('sqlite'); // backticks
new QueryBuilder(); // no quotingPDO compatibility is your responsibility downstream — point any PDO flavor at the generated SQL.
Use RawQuery:
$qb->set('updated_at', $qb->raw('NOW()'));
$qb->where('created_at', '>=', $qb->raw('NOW() - INTERVAL 7 DAY'));See Raw Queries.
$qb->whereIn('user_id', $qb->subQuery(function ($sub) {
$sub->select('id')->from('admins');
}));See Sub Queries.
$qb->where('status', 1)
->group(function ($g) {
$g->where('type', 3)->where('type', 4);
});
// WHERE status = 1 AND (type = 3 AND type = 4)See Grouped Conditions.
Integers are inlined directly into the SQL — they're always numeric, so parameter binding adds no safety. Strings, floats, booleans and other scalar types go through the bag. See Parameters.
Use the dedicated helper:
$qb->whereIsNull('deleted_at');
// WHERE `deleted_at` IS NULLPassing PHP null to where('col', null) would just produce the bare
column reference — use whereIsNull / whereIsNotNull for explicit
NULL checks.
Yes. The value-shortcut swaps the operator and value when:
- you supplied only two arguments, and
- the operator slot is not actually a SQL operator.
See WHERE Clauses § "The value-shortcut".
It does in v2.0.0+. Before v2 there was a long-standing bug (B26) where
the AND-bucket and OR-bucket were joined with " AND ", silently
collapsing top-level orX() calls into AND. Fixed in 2.0.0; see the
CHANGELOG.
Yes. Extend AbstractDriver:
final class OracleDriver extends AbstractDriver
{
protected const NAME = 'oracle';
protected const ESCAPE_CHAR = '"';
}See Drivers § "Adding a custom driver" for the integration patterns.
No — passing null (or any unknown string) gives you GenericDriver,
which does no identifier quoting. Useful for tests or for SQL that
already pre-escapes identifiers.
Yes, for values. Every user value flows through the parameter bag.
The defense breaks down when you pass user input as an identifier
(table or column name) or as a SQL fragment via RawQuery — both are
caller-side responsibilities. See Security for the full threat
model.
It can be, if $_GET['id'] happens to look like 'CURRENT_USER()' or
similar. The library inlines such strings as SQL function calls
(intentional, so programmers can write $qb->set('updated_at', 'NOW()')
without ceremony). Mitigation: always coerce / validate user input
before passing it to a value slot. See Security §V1.
v2.0.0 auto-escapes %, _, and \ inside any user value passed to
the LIKE family. To opt out (e.g. you really want wildcards), pass a
RawQuery. See Security §V4.
Follow the organization-wide disclosure process. Do not open public issues for security problems.
A lot — v2 is a deliberate breaking release. See Migration from v1 for the complete walkthrough.
Yes, the 1.x line still exists on Packagist. But v1 has a documented
SQL-injection vector (FIND_IN_SET) and the LIKE / B26 / B27 footguns,
so upgrading is recommended.
composer install
composer test # phpunit
composer cs # PSR-12
composer stan # PHPStan level 6
composer qa # all of the aboveSee the organization-wide CONTRIBUTING.
Not implemented as a first-class helper. Use RawQuery to append the
tail; see Recipes § "Upsert".
OVER (PARTITION BY ...) clauses aren't first-class but RawQuery slots
right in. See Recipes § "Ranking & windowed counts".
selectMid() emits MySQL's MID(col, offset, length). For
PostgreSQL/SQLite use RawQuery:
$qb->select($qb->raw('SUBSTRING(name FROM 1 FOR 5) AS prefix'));That's a different concern. Reach for a migration library (e.g. Phinx) — the builder is intentionally scope-limited.
Next: Migration from v1
InitORM QueryBuilder — MIT licensed · authored by Muhammet ŞAFAK · part of the InitORM family · report an issue · security disclosure