NSY Model & DB — User Tutorial
Query builder for NSY (System/Core/DB.php, System/Core/NSY_DB.php). Unified via NSY_DB::connect() (single source, declare(strict_types=1), PDO::ERRMODE_EXCEPTION), declare(strict_types=1) in both.
- DB:
System\Core\DB— DML/query (SELECT/INSERT/UPDATE/DELETE) +fetch*,exec,multiInsert - NSY_DB:
System\Core\NSY_DB— low-level factory (mysql/dblib/pgsql/sqlsrv) used byDBandNSY_Migration - Config:
env.phpconnections(4:primary/mysql/pgsql/sqlsrv) +System/Config/App.php(transaction,csrf_token)
Table of Contents
- Connections
- Basic Query
- Binding
- Fetching
- Execute & Multi Insert
- Transactions
- Migrated Connection (NEW)
- Quick Reference
Connections
Connections are declared once in env.php under connections and selected by name.
// env.php
'connections' => [
'primary' => ['DB_CONNECTION' => 'mysql', 'DB_HOST' => 'localhost', 'DB_NAME' => 'nsy', ...],
'secondary' => ['DB_CONNECTION' => 'pgsql', ...],
'mysql' => [...], // blank template
'pgsql' => [...],
'sqlsrv' => [...],
]
DB::connect()->query($q)->fetchAll(); // primary
DB::connect('secondary')->query($q)->fetchAll(); // secondary
DB::connect('pgsql')->query($q)->fetchAll(); // custom
DB::connect(string $conn='primary'): objectSystem/Core/DB.php:33delegates toNSY_DB::connect($conn)System/Core/NSY_DB.php:24— onematchselects the driver (no duplicatedswitch).
Environment keys
| Key | Required | Purpose |
|---|---|---|
DB_CONNECTION |
yes | Driver: mysql, pgsql, dblib or sqlsrv |
DB_HOST |
yes | Server host |
DB_NAME |
yes | Database name |
DB_PORT |
— | Port (appended when filled) |
DB_USER / DB_PASS |
— | Credentials (default '') |
DB_CHARSET |
— | Charset (mysql / pgsql / dblib) |
DB_ATTR |
— | PDO options array, merged over the secure defaults |
Missing DB_CONNECTION, DB_HOST or DB_NAME raises a configuration error through
NSY_Desk::staticErrorHandler().
Supported drivers
DB_CONNECTION |
PDO extension | DSN built by | Format |
|---|---|---|---|
mysql |
pdo_mysql |
buildDsn() |
mysql:host=…;port=…;dbname=…;charset=… |
pgsql |
pdo_pgsql |
buildDsn() |
pgsql:host=…;port=…;dbname=…;charset=… |
dblib |
pdo_dblib |
buildDsn() |
dblib:host=…;port=…;dbname=…;charset=… |
sqlsrv |
pdo_sqlsrv |
buildSqlsrvDsn() |
sqlsrv:Server=host,port;Database=… |
Any other value falls through to handleUnknownDriver() and reports an error.
Connection options
normalizeOptions() applies secure defaults, which your DB_ATTR overrides:
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
Every attempt is logged on the db channel (driver / host / port / dbname + duration) —
credentials are never logged.
Backwards-compatible proxies
NSY_DB also exposes the per-driver entry points connectMysql(), connectDblib() and
connectPgsql() (generic DSN) plus connectSqlsrv() (SQLSRV DSN). They are kept for
backwards compatibility; for new code prefer connect($conn).
Basic Query
$q = 'SELECT * FROM users WHERE id = :id';
DB::connect()->query($q)->vars([':id' => 2])->fetch();
// Same: DB::connect('primary')->query($q)->vars([...])->fetchAll();
query(string $q) validates via is_filled() → NSY_Desk::staticErrorHandler().
Binding
// Simple bind (auto)
$q = "SELECT * FROM users WHERE id = :id";
DB::connect()->query($q)->vars([':id' => 2])->fetch();
// Typed BINDVALUE/BINDPARAM
$vars = [':id' => [2, PAR_INT], ':name' => ['%a%', PAR_STR]];
DB::connect()->query($q)->vars($vars)->bind(BINDVAL)->fetch();
DB::connect()->query($q)->vars($vars)->bind(BINDPAR)->fetch();
Fetching
DB::connect()->query($q)->vars()->style(FETCH_ASSOC)->fetchAll(); // all rows
DB::connect()->query($q)->fetch(); // single row
DB::connect()->query($q)->fetchColumn(0); // single value
DB::connect()->query($q)->rowCount(); // affected rows
// FETCH_* constants: FETCH_NUM, FETCH_ASSOC, FETCH_BOTH, FETCH_COLUMN, FETCH_OBJ, FETCH_KEY_PAIR...
Execute & Multi Insert
// Update/delete/insert
$q = "UPDATE users SET name = :name WHERE id = :id";
DB::connect()->query($q)->vars($p)->bind()->exec(); // true, with transaction + CSRF check
// Multi insert
$q = "INSERT INTO users (id, name, user_name)";
$arr = [[1,'A','a'], [2,'B','b']];
DB::connect()->query($q)->vars($arr)->multiInsert();
exec() checks config_app('csrf_token') via SecurityMiddleware::validateAdvancedCSRF + transaction (on → beginTransaction/commit/rollback).
Transactions
// Auto via config — each exec() write is wrapped on its own
// System/Config/App.php: 'transaction' => config_env('DB_TRANSACTION') ?? 'off'
DB::connect()->query($q)->vars($p)->exec(); // handles begin/commit/rollback internally
Recommended: DB::transaction() commits on success and rolls back + re-throws on error.
use System\Core\DB;
$orderId = DB::transaction(function ($pdo) use ($data) {
$id = qb('orders')->insert($data);
qb('order_items')->insertBatch($items);
return $id;
}); // commits here; on any exception it rolls back and re-throws
Manual control, when you need to decide inside the flow:
DB::beginTransaction();
try {
qb('accounts')->where('id', 1)->decrement('balance', 100);
qb('accounts')->where('id', 2)->increment('balance', 100);
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
throw $e;
}
DB::inTransaction(); // bool — is a transaction open on the shared connection?
DB::transaction()/beginTransaction()/commit()/rollBack()/inTransaction()are the public API and operate on the shared connection, soqb()calls inside the callback join the same transaction. The lower-levelbeginTrans()/commitTrans()/rollbackTrans()areprotected(internal). Do not nestDB::transaction()with the auto mode above (transaction = on).
Migrated Connection (NEW)
Before (duplicated):
switch(config_db(...)) { case 'mysql': NSY_DB::connectMysql(...) }
After (unified):
// System/Core/DB.php:33 & System/Core/NSY_Migration.php:27
NSY_DB::connect(string $conn): ?PDO // match driver → createConnection/buildDsn/normalizeOptions
Benefits: declare(strict_types=1), ?PDO type, buildDsn() + quoteIdent() safety, normalizeOptions() defaults (ERRMODE_EXCEPTION, FETCH_ASSOC).
Quick Reference
| Method | Purpose | Returns |
|---|---|---|
DB::connect($conn) |
Select connection | object |
NSY_DB::connect($conn) |
Driver factory (mysql/pgsql/dblib/sqlsrv) |
?PDO |
query($q) / vars($arr) / bind(BINDVAL) / style(FETCH_ASSOC) |
Build query | object (chainable) |
fetchAll() / fetch() / fetchColumn($i) / rowCount() |
Fetch | array/mixed/int |
exec() / multiInsert() |
Execute DML | bool |
DB::transaction($fn,$conn) |
Run callback in a transaction (commit / rollback+rethrow) | mixed |
DB::beginTransaction() / commit() / rollBack() |
Manual transaction (public API) | bool |
DB::inTransaction() |
Is a transaction open? | bool |
beginTrans() / commitTrans() / rollbackTrans() |
Transaction (protected, internal) | object |
pdoSetAttr($k,$v) |
PDO attribute | object |
Related: System/Core/DB.php:33, System/Core/NSY_DB.php:24, env.php connections, System/Core/NSY_Migration.php (DDL counterpart).