Skip to content

Configuration

Muhammet Şafak edited this page May 24, 2026 · 1 revision

Configuration

A Database is configured through a single credentials array, passed either to DB::createImmutable() or to new Database(...). Every key is forwarded as-is to the underlying InitORM\DBAL\Connection\Connection.

Full reference

Key Type Default What it does
dsn string (built) The PDO DSN. When empty, one is constructed from driver/host/port/database/charset via DBAL's DsnBuilder.
driver string 'mysql' mysql, pgsql / postgres / postgresql, sqlite, or any PDO driver name (oci, sqlsrv, …). Also picks the QueryBuilder dialect for identifier quoting.
host string '127.0.0.1' Ignored when dsn is provided.
port int|string 3306 Ignored when dsn is provided.
database string '' For SQLite use ':memory:' or a file path. Ignored when dsn is provided.
username string|null null
password string|null null
charset string 'utf8mb4' MySQL only: applied via SET NAMES. Pass '' to skip on PostgreSQL/SQLite.
collation string|null null MySQL only. Validated against [A-Za-z0-9_] before interpolation into COLLATE.
options array<int, mixed> [] Merged on top of safe defaults — see below.
queryOptions array<int, mixed> [] PDO prepare() options used for every prepared statement.
log string|callable|object|null null Failure log sink — file path, callable, or any object with a critical(string) method. See Logging and Debug.
debug bool false When true, query failure messages include bound parameters (JSON-encoded). Development only.
queryLogs bool false Bootstrap value for the query log buffer (see Query Profiler).

Safe defaults

Every Database inherits these PDO defaults — they're sane for almost every application:

PDO::ATTR_EMULATE_PREPARES   => false,  // Use server-side prepares on MySQL
PDO::ATTR_PERSISTENT         => false,  // No connection sharing across PHP requests
PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

To override, pass your own options — your values are merged on top, not replaced:

new Database([
    'dsn'     => 'mysql:host=db;dbname=app',
    'options' => [
        PDO::ATTR_PERSISTENT => true,           // override one default
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET time_zone="+00:00"',
    ],
]);

Driver examples

MySQL / MariaDB

new Database([
    'dsn'       => 'mysql:host=db.internal;port=3306;dbname=app;charset=utf8mb4',
    'username'  => 'app',
    'password'  => '',
    'charset'   => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
]);

The charset / collation values produce a SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' right after connecting. Both are validated against [A-Za-z0-9_] so they're safe to interpolate.

PostgreSQL

new Database([
    'dsn'      => 'pgsql:host=db.internal;port=5432;dbname=app',
    'username' => 'app',
    'password' => '',
    'driver'   => 'pgsql',
    'charset'  => '', // not applicable on PostgreSQL
]);

For PostgreSQL, set client_encoding in the DSN if you need a non-default encoding:

pgsql:host=db.internal;dbname=app;options='--client_encoding=UTF8'

SQLite

new Database([
    'driver'   => 'sqlite',
    'database' => __DIR__ . '/var/app.sqlite', // or ':memory:'
    'charset'  => '',
]);

For SQLite, no DSN is needed — DBAL builds sqlite:/path/to/file automatically. Always pass 'charset' => '' to skip the MySQL-only SET NAMES call.

DSN: explicit vs auto-built

Two equivalent setups:

A. Explicit DSN (best when you want full control or use vendor-specific options):

new Database([
    'dsn'      => 'mysql:host=db;port=3306;dbname=app;charset=utf8mb4',
    'username' => 'app',
    'password' => 'secret',
]);

B. Auto-built DSN (cleaner for the common case):

new Database([
    'driver'   => 'mysql',
    'host'     => 'db',
    'port'     => 3306,
    'database' => 'app',
    'charset'  => 'utf8mb4',
    'username' => 'app',
    'password' => 'secret',
]);

When dsn is empty, DBAL's DsnBuilder constructs one from driver / host / port / database / charset.

Per-environment configuration

Wrap the array in your existing config loader. With PHP-DI:

return [
    Database::class => fn (ContainerInterface $c) => new Database([
        'dsn'      => $c->get('env')->get('DB_DSN'),
        'username' => $c->get('env')->get('DB_USER'),
        'password' => $c->get('env')->get('DB_PASS'),
        'debug'    => $c->get('env')->getBool('APP_DEBUG'),
        'log'      => $c->get(LoggerInterface::class),
    ]),
];

With plain PHP and the static facade:

DB::createImmutable([
    'dsn'      => getenv('DB_DSN') ?: 'mysql:host=localhost;dbname=app',
    'username' => getenv('DB_USER') ?: 'app',
    'password' => getenv('DB_PASS') ?: '',
    'debug'    => getenv('APP_DEBUG') === '1',
]);

Switching credentials after construction

Most setters on the underlying Connection (setDatabase(), setHost(), …) throw if PDO has already opened a connection. This is by design: silent credential swaps are a security hazard.

If you need a fresh credentials profile, build a fresh Database (or call disconnect() on the connection first):

$db->getConnection()->disconnect();
$db->getConnection()->setDatabase('analytics');

See also

  • Logging and Debug — every option for the log and debug keys
  • Multiple Connections — running more than one Database side-by-side
  • FAQ — answers to "why does it default to utf8mb4?", "how do I change the timezone?", etc.

Clone this wiki locally