Skip to content
Muhammet Şafak edited this page May 24, 2026 · 2 revisions

InitORM ORM — Wiki

initorm/orm is the top layer of the InitORM stack. It adds active-record-style models and per-row entities on top of initorm/database, and ships:

  • Model + Entity pattern — one class per table, one class per row.
  • CRUD methodscreate, createBatch, read, update, updateBatch, delete, save.
  • Auto timestampscreated_at, updated_at, deleted_at.
  • Soft deletes with onlyDeleted() / ignoreDeleted() / purge.
  • Per-operation permission gates — read-only, write-only, etc., enforced with typed exceptions.
  • Accessor/mutator hooks on entities — getColumnAttribute() / setColumnAttribute().
  • Full query-builder surface — every select / where / join / orderBy / … method from the builder is callable directly on a model thanks to __call forwarding.
use InitORM\Database\Facade\DB;
use App\Model\Posts;

DB::createImmutable([
    'dsn'      => 'mysql:host=localhost;dbname=app;charset=utf8mb4',
    'username' => 'app',
    'password' => 'secret',
]);

$posts = new Posts();

$entities = $posts
    ->where('status', '=', 'published')
    ->orderBy('id', 'DESC')
    ->limit(10)
    ->read()           // hydrates as PostEntity instances
    ->rows();

How to read this wiki

If you are brand new:

  1. Installation — install and verify your driver.
  2. Getting Started — your first model and entity in ten minutes.
  3. Defining Models — every configurable property, explained.
  4. Entities — the attribute bag, accessors, mutators, dirty tracking.

If you have a specific question:

Question Page
"How do I run INSERT / UPDATE / DELETE on a model?" CRUD Operations
"How do I auto-fill created_at / updated_at?" Timestamps
"How do soft deletes work?" Soft Deletes
"How do I read only soft-deleted rows?" Soft Deletes
"How do I add a getNameAttribute() accessor?" Entities
"How do I write a mutator without infinite recursion?" Entities (the setAttribute rule)
"How do I make a model read-only / append-only?" Permission Gates
"How do I write WHERE … ORDER BY … LIMIT on a model?" Query Builder Integration
"Can I use a different database per model?" Multiple Connections
"How do I test models without a real database?" Testing
"How does the __call magic work end-to-end?" Architecture
"What exception fires when X?" Exceptions
"Is X possible? Why does Y throw?" FAQ
"How do I do pagination / chunking / batch upserts on a model?" Recipes

If you are upgrading from v1:

If you are contributing:

  • Contributing — testing patterns, PR process, quality bar.

What this package is not

  • Not a connection or query layer. The connection lifecycle lives in initorm/dbal, the SQL string assembly in initorm/query-builder, and the glue (__call forwarding, CRUD shortcuts, transactions, query log) in initorm/database.
  • Not a migration tool, schema dumper, or fixture loader.
  • Not a relationship manager. There is no hasMany, belongsTo, or eager loading. Use the query-builder's join() family directly — see Query Builder Integration.
  • Not a validation layer. Validate inputs upstream of the model.

The InitORM stack at a glance

┌────────────────────────────────────────────────────────┐
│ initorm/orm           ← ★ you are here                 │
│   Model + Entity active-record API                     │
├────────────────────────────────────────────────────────┤
│ initorm/database      ← CRUD + transaction + facade    │
├────────────────────┬───────────────────────────────────┤
│ initorm/dbal       │ initorm/query-builder             │
│   Connection (PDO) │   QueryBuilder (SQL assembly)     │
│   DataMapper       │   Compilers (string-join)         │
└────────────────────┴───────────────────────────────────┘

Pick any layer — they don't force you to use the one above. If you want raw query control with no model overhead, drop down to $model->getDatabase() and call read()/query() directly.

Package status

Clone this wiki locally