Skip to content

Getting Started

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

Getting Started

A guided ten-minute tour. Every snippet below is real, working code; copy-paste should run unchanged after Installation.

Two usage styles

InitORM Database supports both an instance API and a static facade. They are equally first-class; pick whichever fits your codebase.

Style Best for Drawback
new Database(...) DI-driven apps, libraries, multi-connection setups One extra constructor argument to thread around
DB::createImmutable(...) then DB::... Scripts, CLI tools, smaller apps with one database Single global instance per process

We'll start with the facade because it's the shortest demo. See Static Facade for the full picture.

1. Connect

<?php
require_once 'vendor/autoload.php';

use InitORM\Database\Facade\DB;

DB::createImmutable([
    'dsn'       => 'mysql:host=localhost;port=3306;dbname=demo;charset=utf8mb4',
    'username'  => 'demo',
    'password'  => 'demo',
    'charset'   => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
]);

createImmutable() is single-shot — a second call throws. If you really need to swap (most commonly in tests), use DB::replaceImmutable($connection).

2. Create a table (raw SQL)

DB::query('
    CREATE TABLE IF NOT EXISTS users (
        id     INT AUTO_INCREMENT PRIMARY KEY,
        name   VARCHAR(80)  NOT NULL,
        email  VARCHAR(120) NOT NULL,
        active TINYINT(1)   NOT NULL DEFAULT 1,
        score  INT
    ) ENGINE=InnoDB
');

DB::query() is the universal escape hatch — anything PDO can prepare, you can run.

3. Insert (CRUD shortcut)

DB::create('users', [
    'name'   => 'Alice',
    'email'  => 'alice@example.com',
    'active' => 1,
    'score'  => 42,
]);

echo DB::insertId(); // "1"

Generated SQL: INSERT INTO users (name, email, active, score) VALUES (:name, :email, :active, :score)

4. Insert multiple rows (batch)

DB::createBatch('users', [
    ['name' => 'Bob',   'email' => 'bob@example.com',   'active' => 1, 'score' => 13],
    ['name' => 'Carol', 'email' => 'carol@example.com', 'active' => 0, 'score' => 99],
]);

Compiled to a single multi-row INSERT — much faster than three separate statements.

5. Read

$rows = DB::select('id', 'name', 'score')
    ->from('users')
    ->where('active', '=', 1)
    ->orderBy('score', 'DESC')
    ->limit(10)
    ->read()
    ->asAssoc()
    ->rows();

print_r($rows);

The chain reads like a sentence. Every method that returns the builder (most of them) is re-wrapped to return the Database, so .read() works at the end.

You can also pass the table to read() directly and skip the from():

DB::select('id', 'name')->where('active', '=', 1)->read('users');

6. Update

DB::update('users', ['active' => 0], ['id' => 2]);

Or builder-first:

DB::where('email', 'LIKE', '%@example.com')->update('users', ['active' => 0]);

Both produce a parameterized UPDATE … SET … WHERE ….

7. Delete

DB::delete('users', ['id' => 3]);

A DELETE without a WHERE compiles to … WHERE 1 (intentional, but you almost never want that — callers are responsible for gating).

8. Transactions

use InitORM\Database\Exceptions\DatabaseException;

try {
    DB::transaction(function ($db) {
        $db->create('users', ['name' => 'Dan', 'email' => 'dan@example.com']);
        $db->create('users', ['name' => 'Eve', 'email' => 'eve@example.com']);

        if (rand(0, 1) === 0) {
            throw new \RuntimeException('rollback please');
        }
    });
} catch (DatabaseException $e) {
    echo "transaction failed: " . $e->getPrevious()?->getMessage();
}

Throwing inside the closure rolls the transaction back. The original exception is reachable via getPrevious() — failures are never silently swallowed.

9. Profile what you ran

DB::enableQueryLog();

DB::read('users', ['id'], ['active' => 1]);
DB::read('users', ['id'], ['active' => 0]);

print_r(DB::getQueryLogs());

Each entry has query, args, and timer (seconds). Useful for finding N+1 problems; see Query Profiler.

What now?

Clone this wiki locally