ORM & Models


Overview

Lyger’s ORM is inspired by Laravel’s Eloquent. Each database table has a corresponding Model class that provides an expressive, fluent interface for querying and mutating data.


Defining a Model

Generate a model with the CLI:

php rawr make:model Post
php rawr make:model Post --migration   # Also creates a migration

A model lives in App/Models/ and extends Lyger\Database\Model:

<?php

namespace App\Models;

use Lyger\Database\Model;

class Post extends Model
{
    // Table name (optional — auto-derived: 'Post' → 'posts')
    protected string $table = 'posts';

    // Columns that can be mass-assigned
    protected array $fillable = ['title', 'content', 'user_id', 'published'];

    // Columns hidden from toArray()/toJson()
    protected array $hidden = [];

    // Automatic type casting
    protected array $casts = [
        'published' => 'bool',
        'user_id'   => 'int',
        'metadata'  => 'array',     // JSON stored as array
    ];

    // Auto-manage created_at / updated_at
    protected bool $timestamps = true;
}

Table Name Convention

Model Class Default Table
User users
Post posts
BlogPost blog_posts
OrderItem order_items

Override with protected string $table = 'custom_table';.


Creating Records

// Mass assignment (uses $fillable)
$post = Post::create([
    'title'   => 'Hello World',
    'content' => 'My first post.',
    'user_id' => 1,
]);

// Instantiate and save
$post = new Post();
$post->title   = 'Hello World';
$post->content = 'My first post.';
$post->save();

Reading Records

// Find by primary key
$post = Post::find(1);          // Returns null if not found
$post = Post::findOrFail(1);    // Throws exception if not found

// All records
$posts = Post::all();           // Returns a Collection

// Using the query builder
$posts = Post::query()
    ->where('published', true)
    ->orderBy('created_at', 'DESC')
    ->limit(10)
    ->get();

Updating Records

// Direct property mutation
$post = Post::find(1);
$post->title = 'Updated Title';
$post->save();

// Mass assignment
$post->fill(['title' => 'New Title', 'content' => 'New content.']);
$post->save();

Deleting Records

$post = Post::find(1);
$post->delete();

If your table has a deleted_at column (soft deletes via $table->softDeletes()), delete() sets the timestamp instead of removing the row.


Checking if Model is Persisted

// New vs saved
$post = new Post(['title' => 'Draft']);
$post->getKey(); // null — not yet saved

$post->save();
$post->getKey(); // 1 — now has an ID

Type Casting

Configure $casts to auto-convert column values:

protected array $casts = [
    'age'       => 'int',
    'price'     => 'float',
    'is_active' => 'bool',
    'settings'  => 'array',   // JSON string ↔ PHP array
    'metadata'  => 'json',    // Alias for array
    'born_at'   => 'datetime',
];

Values are cast automatically when accessed via $model->attribute:

$user->age;       // int(25), not string '25'
$user->is_active; // bool(true), not string '1'
$user->settings;  // array(['theme' => 'dark']), not JSON string

Serialization

$post->toArray();           // Array (respects $hidden)
$post->toJson();            // JSON string
$post->toJson(JSON_PRETTY_PRINT);  // Pretty-printed JSON

Relationships

Has One

class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class, 'user_id');
    }
}

$profile = User::find(1)->profile();

Has Many

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class, 'user_id');
    }
}

$posts = User::find(1)->posts(); // Returns array of Posts

Belongs To

class Post extends Model
{
    public function author()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}

$author = Post::find(1)->author();

Belongs To Many

class Post extends Model
{
    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'post_tag');
    }
}

$tags = Post::find(1)->tags(); // Through pivot table 'post_tag'

Collections

Model::all() and query results return a Collection object with chainable methods:

$posts = Post::all();

// Filter
$published = $posts->filter(fn($p) => $p['published'] === true);

// Map
$titles = $posts->map(fn($p) => $p['title']);

// Pluck a column
$ids = $posts->pluck('id');

// Sort
$sorted = $posts->sortBy('created_at');

// Paginate-like operations
$first5 = $posts->take(5);

// Serialize
$array = $posts->toArray();
$json  = $posts->toJson();

See the Query Builder doc for filtering before fetching from the database.


Mass Assignment Protection

Only columns listed in $fillable can be set via create() or fill():

protected array $fillable = ['name', 'email'];

// 'is_admin' is NOT in $fillable → silently ignored
User::create(['name' => 'Alice', 'email' => 'alice@test.com', 'is_admin' => true]);

Model Properties Reference

Property Type Description
$table string Table name (auto-derived if omitted)
$primaryKey string Primary key column (default: 'id')
$fillable array Mass-assignable columns
$hidden array Columns excluded from serialization
$casts array Column type casting map
$dates array Date columns (default: ['created_at','updated_at','deleted_at'])
$timestamps bool Auto-manage timestamps (default: true)

Static Method Reference

Method Description
find($id): ?static Find by primary key or null
findOrFail($id): static Find by primary key or throw
all(): Collection All rows as Collection
create(array $attributes): static Insert and return model
query(): QueryBuilder Start a fluent query
getTable(): string Get resolved table name

Instance Method Reference

Method Description
fill(array $attrs): self Mass-assign (respects $fillable)
save(): bool INSERT (new) or UPDATE (existing)
delete(): bool Delete or soft-delete row
toArray(): array Serialize to array
toJson(int $opts = 0): string Serialize to JSON
getKey(): mixed Get primary key value
hasOne(string $related, ?string $fk): HasOne Define has-one relation
hasMany(string $related, ?string $fk): HasMany Define has-many relation
belongsTo(string $related, ?string $fk): BelongsTo Define belongs-to relation
belongsToMany(string $related, ?string $pivot): BelongsToMany Define many-to-many relation

Copyright © 2026 Lyger Framework. Distributed under the MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.