Auto-gegenereerd via Reflection — blijft altijd in sync met src/.
Adapter
Framework\Db\AdapterDunne wrapper rond een PDO-connectie.
Doel: één plek voor de PDO-instance (kernel-service `$kernel->db`),
een transactional helper, en een `into:`-parameter zodat queries direct
een specifieke klasse of callable als rij-prototype kunnen krijgen
(zoals legacy `Db\Adapter\PDO::query(..., ['prototype' => ...])`).
`query()` returnt een `PDOStatement` zodat alle native PDO-features
(`fetchAll`, `fetch`, foreach-iteratie, rowCount, errorInfo, …) gewoon
werken zonder extra abstractie-laag.
$db = new Adapter($pdo);
// stdClass per rij (PDO default na FETCH_OBJ in Bootstrap)
$rows = $db->query('SELECT * FROM users WHERE active = ?', [1])->fetchAll();
// Hydrate naar een klasse — PDO::FETCH_CLASS
$rows = $db->query($sql, $params, into: User::class)->fetchAll();
// Custom builder — PDO::FETCH_FUNC, perfect voor readonly objects
$rows = $db->query($sql, $params,
into: fn($id, $name) => new User(id: $id, name: $name)
)->fetchAll();
// Transactional block
$id = $db->transactional(fn() => $repo->insert([...]));
Voor query-timing/logging: wrap in `ProfilingAdapter` (zelfde interface).
__construct(PDO $pdo)4 public methods
lastInsertId(): intpdo(): PDOEscape-hatch voor code die direct PDO nodig heeft.
query(string $sql, array $params = array (
), callable|string|null $into = NULL): PDOStatementVoer een query uit met optionele bind-params en optioneel rij-prototype.
transactional(callable $fn): ?mixedVoer `$fn` uit binnen een transactie. Bij exception: rollback en re-throw.
Genest aanroepen wordt als no-op behandeld (de outer transactie wint).
Operator
Framework\Db\OperatorVergelijkings-operators voor {@see Query}.
Gevangen in een enum zodat de SQL-compiler een gesloten set kan
accepteren — geen string-injectie via een onbekende operator.
4 public methods
static cases(): arraystatic from(string|int $value): staticstatic from2(string $op): selfResolve een loose string naar een case (case-insensitive, '<>' alias).
static tryFrom(string|int $value): ?staticEq, NotEq, Lt, Lte, Gt, Gte, Like, NotLike, In, NotIn, IsNull, IsNotNull, BetweenProfilingAdapter
Framework\Db\ProfilingAdapterAdapter-decorator die elke query timed en via een PSR-3 logger logt.
$db = new ProfilingAdapter($pdo, $logger);
$db->query('SELECT 1');
// Log-line: "DB query (1.2ms) SELECT 1" met context [duration_ms, params]
Vervangt legacy `Db\Profiler` — die schreef naar eigen output, deze gaat
door dezelfde PSR-3 logger als de rest van het framework. Niveau is per
default DEBUG; te overriden via constructor.
Profiling stats (totaal-aantal queries, totale tijd) leven op het object;
`stats()` geeft 'm terug. Geen autoflush — caller bepaalt wanneer.
__construct(PDO $pdo, \LoggerInterface $logger, string $level = 'debug')3 public methods
query(string $sql, array $params = array (
), callable|string|null $into = NULL): PDOStatementresetStats(): voidstats(): arrayQuery
Framework\Db\QueryFluent, immutable query-builder boven {@see TableRepository}.
Twee groeperings-stijlen:
// closure
->whereGroup(fn(Query $q) => $q->where('age', '>=', 18)->orWhere('parent', 1))
// nest()/unnest() — geleend van legacy/library/Db/Predicate
->nest()->where('age', '>=', 18)->orWhere('parent', 1)->unnest()
Beide produceren `(...)`-groeperingen in de SQL.
__construct(PDO $pdo, string $table, string $pk = 'id')26 public methods
count(): intdelete(): intMassa-delete binnen het filter. Gooit exceptie zonder filter; gebruik
`->deleteAll()` voor truncate-achtige actie.
deleteAll(): intexists(): boolfirst(): ?arrayget(): arraylimit(int $limit, int $offset = 0): staticnest(string $combiner = 'AND'): staticOpen een nieuwe group; returned de inner Query. Sluiten met `unnest()`.
orNest(): staticorWhere(string $column, ?mixed $opOrValue, ?mixed $value = NULL): staticorWhereGroup(callable $build): staticorderBy(string $column, string $direction = 'asc'): staticpaginate(int $page = 1, int $perPage = 20): arrayPagineer: returnt items + meta (page, perPage, total, totalPages, hasMore).
toSql(): arrayunnest(): staticSluit een nest af en returneer de parent met de child-children gekopieerd.
update(array $data): intMassa-update binnen het filter. Gooit een exceptie wanneer er geen filter is —
gebruik `->updateAll($data)` om dat bewust te accepteren.
updateAll(array $data): intwhere(string $column, ?mixed $opOrValue, ?mixed $value = NULL): staticwhere(col, value) → '='
where(col, op, value)
whereBetween(string $column, ?mixed $from, ?mixed $till): staticwhereGroup(callable $build, string $combiner = 'AND'): staticGroup via closure. De callback krijgt een verse Query en moet de
gebouwde Query returnen (omdat de builder immutable is).
->whereGroup(fn($q) => $q->where('age', '>=', 18)->orWhere('parent', 1))
whereIn(string $column, array $values): staticwhereLike(string $column, string $pattern): staticwhereNotIn(string $column, array $values): staticwhereNotLike(string $column, string $pattern): staticwhereNotNull(string $column): staticwhereNull(string $column): staticSql
Framework\Db\SqlPure SQL-compiler. Krijgt geserialiseerde where-nodes binnen,
spuugt SQL-fragments uit met PDO-positional-params.
Geen DB-toegang; volledig testbaar.
6 public methods
static compileAssignments(array $data): arraySET-clausule voor UPDATE/INSERT.
static compileLimit(?int $limit, int $offset = 0): stringstatic compileOrderBy(array $orders): stringBouw ORDER BY clausule. Accepteert ['col' => 'asc'|'desc'] map.
static compileWhere(array $nodes): arrayCompileer een where-tree naar SQL + params.
Tree-structuur (gemaakt door Query):
['type' => 'leaf'|'group', ...]
leaf: ['type' => 'leaf', 'combiner' => 'AND'|'OR', 'column' => string,
'op' => Operator, 'value' => mixed]
group: ['type' => 'group', 'combiner' => 'AND'|'OR', 'children' => list<node>]
static quoteColumn(string $name): stringstatic quoteTable(string $name): stringTableRepository
Framework\Db\TableRepositoryGenerieke repository voor "normale" tabellen — geen DynamicItems.
$members = new TableRepository($pdo, 'members');
$me = $members->find(42);
$id = $members->insert(['email' => 'jan@x.nl', 'name' => 'Jan']);
$members->update(42, ['name' => 'Jan Jansen']);
$members->delete(42);
$rows = $members->query()
->where('active', 1)
->whereIn('country', ['nl', 'be'])
->orderBy('name')
->limit(20)
->get();
$page = $members->query()->where('active', 1)->paginate(page: 2, perPage: 20);
Veldnamen worden gevalideerd via {@see Sql::COLUMN_REGEX} (anti-injection).
Optioneel `->columns([...])` om verder strikt te whitelisten.
Events (alleen wanneer `EventDispatcherInterface` is geïnjecteerd):
- BeforeInsertEvent / AfterInsertEvent
- BeforeUpdateEvent / AfterUpdateEvent
- BeforeDeleteEvent / AfterDeleteEvent
__construct(PDO $pdo, string $table, string $pk = 'id', ?\EventDispatcherInterface $events = NULL)11 public methods
columns(array $columns): selfSchakel een strikte kolom-whitelist in.
countBy(array $criteria = array (
)): intdelete(string|int $id): boolfind(string|int $id): ?arrayfindBy(array $criteria, ?int $limit = NULL): arrayfindOneBy(array $criteria): ?arrayinsert(array $data): string|intquery(): \Querytransactional(callable $fn): ?mixedRoep $fn aan binnen één PDO-transactie. Bij exception → rollback.
update(string|int $id, array $data): boolupsert(array $data, array $on): string|intAfterDeleteEvent
Framework\Events\Db\AfterDeleteEvent__construct(string $table, string|int $id, int $affected)AfterInsertEvent
Framework\Events\Db\AfterInsertEvent__construct(string $table, string|int $id, array $data)AfterUpdateEvent
Framework\Events\Db\AfterUpdateEvent__construct(string $table, string|int $id, array $data, int $affected)BeforeDeleteEvent
Framework\Events\Db\BeforeDeleteEvent__construct(string $table, string|int $id)BeforeInsertEvent
Framework\Events\Db\BeforeInsertEventGefired vóór een TableRepository::insert(). Listeners mogen `$data` muteren
via setData() — handig voor tijdstempels of audit-velden.
__construct(string $table, array $data)2 public methods
getData(): arraysetData(array $data): voidBeforeUpdateEvent
Framework\Events\Db\BeforeUpdateEvent__construct(string $table, string|int $id, array $data)2 public methods
getData(): arraysetData(array $data): void