Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
Models
A Model binds one database table and exposes the same CRUD surface as DB::, with a few model-only conveniences layered on top:
- Configurable primary key column.
- Auto-derived schema name (
PostComment→post_comment) when you don't set one. - Soft deletes (
deleted_atcolumn). - Timestamps — auto-managed
created_at/updated_at. - Per-operation access gates (
$readable,$writable,$updatable,$deletable). - An Entity class used to hydrate
read()results.
namespaceApp\Model;
useInitPHP\Database\Model;
finalclass Posts extends Model
{
protectedstring$schema = 'posts';
protectedstring$schemaId = 'id';
}The base constructor binds the model to the shared DB::getDatabase() instance — so as long as DB::createImmutable([...]) ran during bootstrap, no extra wiring is needed:
$posts = newApp\Model\Posts();
$posts->create(['title' => 'Hello', 'content' => 'World']);If you omit $schema, the constructor derives it from the class' short name using Helper::camelCaseToSnakeCase():
| Class | Derived schema |
|---|---|
Posts | posts |
BlogPost | blog_post |
UserProfile | user_profile |
APIToken | api_token |
finalclass BlogPost extends \InitPHP\Database\Model {}
(newBlogPost())->getSchema(); // 'blog_post'namespaceApp\Model;
useApp\Entity\PostEntity;
useInitPHP\Database\Model;
finalclass Posts extends Model
{
// Optional. Defaults to the snake_case form of the class' short name.protectedstring$schema = 'posts';
// Primary key column. Set to '' to disable the PK lift-out in update().protectedstring$schemaId = 'id';
// Entity class used by read() to hydrate rows.// Defaults to InitPHP\Database\Entity.protectedstring$entity = PostEntity::class;
// Soft deletes — see Soft-Deletes page.protectedbool$useSoftDeletes = true;
protected ?string$deletedField = 'deleted_at';
// Timestamp columns — see Timestamps page.protected ?string$createdField = 'created_at';
protected ?string$updatedField = 'updated_at';
protectedstring$timestampFormat = 'Y-m-d H:i:s';
// Access gates. Setting any of these to false throws on the matching call.protectedbool$readable = true;
protectedbool$writable = true;
protectedbool$updatable = true;
protectedbool$deletable = true;
// Use a non-default connection — see Multiple-Connections.protected ?array$credentials = null;
}$posts = newApp\Model\Posts();
// Insert; $createdField is filled in automatically when set.$posts->create(['title' => 'Hello', 'content' => 'World']);
// Select; soft-deleted rows are excluded automatically.$rows = $posts->read(['id', 'title'], ['status' => 1])
->asAssoc()
->rows();
// Update; if the primary key sits in $set, it is lifted into a WHERE// clause and removed from the SET map.$posts->update(['id' => 13, 'title' => 'New title']);
// Or pass conditions explicitly:$posts->update(['title' => 'New title'], ['id' => 13]);
// Delete; soft-deletes when $useSoftDeletes = true, hard-deletes otherwise.$posts->delete(['id' => 13]);
$posts->delete(['id' => 13], purge: true); // force a real DELETEEvery method that does not live on Model itself falls through to the underlying Database, and chainable builder calls re-wrap to return the Model so the chain stays type-consistent:
$rows = $posts
->select('id', 'title', 'created_at')
->where('status', 1)
->orderBy('created_at', 'DESC')
->limit(20)
->read()
->asAssoc()
->rows();When $entity points at a subclass of InitPHP\Database\Entity, read() hydrates rows into instances of that class:
foreach ($posts->read() as$post) {
echo$post->title, PHP_EOL;
}->read() returns a DataMapperInterface, which is iterable — each iteration gives back one entity. For the full attribute / accessor / mutator story, see Entities.
$entity = newPostEntity(['title' => 'New post']);
$posts->save($entity); // no id ⇒ create()$entity = newPostEntity(['id' => 13, 'title' => 'Edited']);
$posts->save($entity); // id present ⇒ update()save() checks the entity for a value at $schemaId: present (non-null, non-empty-string) ⇒ update; absent ⇒ create. Useful in a controller that handles both flows with the same method body.
Each gate is a boolean on the subclass; flipping any to false makes the matching call throw:
protected bool $readable = true;
protected bool $writable = true;
protected bool $updatable = true;
protected bool $deletable = true;| Gate | Disabled call throws |
|---|---|
$readable = false | read() → InitORM\ORM\Exceptions\ReadableException |
$writable = false | create() / createBatch() → WritableException |
$updatable = false | update() / updateBatch() → UpdatableException |
$deletable = false | delete() → DeletableException |
Handy for read-only views ($writable = $updatable = $deletable = false) or audit-log tables that must never be updated after insert ($updatable = $deletable = false).
$db = $posts->getDatabase(); // InitORM\Database\Interfaces\DatabaseInterface$db->transaction(function () use ($posts) {
$posts->create([...]);
});Useful for transaction boundaries and for sharing the same connection across two models.
Each Model instance is bound to one Database. Builder state on that Database resets after every read() / create() / update() / delete() — so two model instances sharing the same underlying Database will not bleed into each other's queries, as long as one method runs at a time.
If you really need parallel chains, request a fresh builder:
$model->getDatabase()->withFreshBuilder();- Entities — the row container that pairs with
$entity. - Soft Deletes — the full soft-delete protocol.
- Timestamps —
createdField/updatedFieldmechanics. - Multiple Connections —
protected ?array $credentials. - Recipe — Repository Pattern — when active record is the wrong shape.
initphp/database · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Core API
ORM
Advanced
DataTables Helper
Recipes
- Index
- — Pagination
- — Search & Filters
- — Upsert / REPLACE INTO
- — Audit Log
- — DataTables Bootstrap
- — Repository Pattern
Reference
Migration & Help