Introduction
Eloquent is Lyger’s implementation of the Active Record pattern, providing an elegant and expressive way to interact with your database. Each database table has a corresponding Model class that is used to interact with that table.
Defining Models
Basic Model Definition
Create a model by extending the Lyger\Database\Model class:
<? php
namespace App\Models ;
use Lyger\Database\ Model ;
class User extends Model
{
protected string $table = 'users' ;
protected string $primaryKey = 'id' ;
protected array $fillable = [ 'name' , 'email' , 'password' ];
protected array $hidden = [ 'password' ];
protected bool $timestamps = true ;
}
If you don’t specify a $table property, Eloquent will automatically use the lowercase, pluralized class name (e.g., User becomes users).
Model Properties
Table Name
// Explicitly set table name
protected string $table = 'users' ;
Primary Key
// Default is 'id'
protected string $primaryKey = 'id' ;
// Custom primary key
protected string $primaryKey = 'user_id' ;
Fillable Attributes
Define which attributes can be mass-assigned:
protected array $fillable = [ 'name' , 'email' , 'password' , 'status' ];
Only attributes listed in $fillable can be set via create() or fill() methods. This protects against mass-assignment vulnerabilities.
Hidden Attributes
Hide attributes when converting to array or JSON:
protected array $hidden = [ 'password' , 'secret_token' ];
Timestamps
// Enable automatic timestamp management (default: true)
protected bool $timestamps = true ;
// Disable timestamps
protected bool $timestamps = false ;
When enabled, Eloquent automatically manages created_at and updated_at columns.
Attribute Casting
Cast attributes to specific types:
protected array $casts = [
'id' => 'int' ,
'email_verified' => 'bool' ,
'price' => 'float' ,
'options' => 'array' ,
'metadata' => 'json' ,
'published_at' => 'datetime'
];
Supported casts: int, integer, float, double, bool, boolean, string, array, json, datetime, date
Retrieving Models
Find by Primary Key
// Find by ID (returns null if not found)
$user = User :: find ( 1 );
// Find or throw exception
$user = User :: findOrFail ( 1 ); // Throws RuntimeException if not found
Retrieving All Records
$users = User :: all ();
foreach ( $users as $user ) {
echo $user -> name ;
}
Using Query Builder Methods
All Query Builder methods are available on models:
// Where clauses
$activeUsers = User :: query ()
-> where ( 'status' , '=' , 'active' )
-> get ();
// Ordering
$recentUsers = User :: query ()
-> latest ( 'created_at' )
-> limit ( 10 )
-> get ();
// Multiple conditions
$admins = User :: query ()
-> where ( 'role' , '=' , 'admin' )
-> whereNotNull ( 'email_verified_at' )
-> orderBy ( 'name' , 'ASC' )
-> get ();
Creating Models
Using Create Method
$user = User :: create ([
'name' => 'John Doe' ,
'email' => 'john@example.com' ,
'password' => password_hash ( 'secret' , PASSWORD_DEFAULT )
]);
Using Save Method
$user = new User ();
$user -> name = 'Jane Doe' ;
$user -> email = 'jane@example.com' ;
$user -> password = password_hash ( 'secret' , PASSWORD_DEFAULT );
$user -> save ();
Using Fill Method
$user = new User ();
$user -> fill ([
'name' => 'Bob Smith' ,
'email' => 'bob@example.com'
]);
$user -> password = password_hash ( 'secret' , PASSWORD_DEFAULT );
$user -> save ();
The create() and fill() methods only work with attributes listed in the $fillable property.
Updating Models
Update Using Save
$user = User :: find ( 1 );
$user -> name = 'Updated Name' ;
$user -> email = 'newemail@example.com' ;
$user -> save ();
Mass Update via Query
User :: query ()
-> where ( 'status' , '=' , 'pending' )
-> update ([ 'status' => 'active' ]);
Deleting Models
Delete Single Model
$user = User :: find ( 1 );
$user -> delete ();
Delete via Query
User :: query ()
-> where ( 'status' , '=' , 'inactive' )
-> where ( 'last_login' , '<' , date ( 'Y-m-d' , strtotime ( '-1 year' )))
-> delete ();
Accessing Attributes
Magic Properties
$user = User :: find ( 1 );
// Get attributes
echo $user -> name ;
echo $user -> email ;
// Set attributes
$user -> name = 'New Name' ;
$user -> status = 'active' ;
Array Access
// Check if attribute exists
if ( isset ( $user -> email )) {
echo $user -> email ;
}
// Unset attribute
unset ( $user -> temporary_field );
Serialization
To Array
$user = User :: find ( 1 );
$array = $user -> toArray ();
// Hidden attributes are excluded
// Casted attributes are converted to their target types
To JSON
$user = User :: find ( 1 );
$json = $user -> toJson ();
// Or with options
$json = $user -> toJson ( JSON_PRETTY_PRINT );
Collections
Eloquent returns a Collection instance for multi-record results:
$users = User :: all ();
// Collection methods
$count = $users -> count ();
$first = $users -> first ();
$last = $users -> last ();
$isEmpty = $users -> isEmpty ();
// Map over collection
$names = $users -> map ( fn ( $user ) => $user -> name );
// Filter collection
$admins = $users -> filter ( fn ( $user ) => $user -> role === 'admin' );
// Pluck specific attribute
$emails = $users -> pluck ( 'email' );
// Where on collection
$active = $users -> where ( 'status' , '=' , 'active' );
// Sort collection
$sorted = $users -> sortBy ( 'name' );
$sortedDesc = $users -> sortByDesc ( 'created_at' );
// Take first N items
$topTen = $users -> take ( 10 );
// Convert to array/JSON
$array = $users -> toArray ();
$json = $users -> toJson ();
Model Methods
Getting the Primary Key
$user = User :: find ( 1 );
$id = $user -> getKey (); // Returns primary key value
$keyName = $user -> getPrimaryKey (); // Returns 'id'
Getting the Table Name
$tableName = $user -> getTableName ();
// Or statically
$tableName = User :: getTable ();
Complete Example
Here’s a comprehensive example demonstrating Eloquent usage:
<? php
namespace App\Models ;
use Lyger\Database\ Model ;
class Post extends Model
{
protected string $table = 'posts' ;
protected array $fillable = [
'title' ,
'slug' ,
'content' ,
'status' ,
'user_id' ,
'published_at'
];
protected array $hidden = [
'deleted_at'
];
protected array $casts = [
'id' => 'int' ,
'user_id' => 'int' ,
'published' => 'bool' ,
'published_at' => 'datetime' ,
'metadata' => 'json'
];
protected bool $timestamps = true ;
}
use App\Models\ Post ;
// Create a new post
$post = Post :: create ([
'title' => 'Getting Started with Lyger' ,
'slug' => 'getting-started-with-lyger' ,
'content' => 'Lyger is a modern PHP framework...' ,
'status' => 'published' ,
'user_id' => 1 ,
'published_at' => date ( 'Y-m-d H:i:s' )
]);
// Find and update
$post = Post :: find ( 1 );
$post -> title = 'Updated Title' ;
$post -> save ();
// Query posts
$publishedPosts = Post :: query ()
-> where ( 'status' , '=' , 'published' )
-> whereNotNull ( 'published_at' )
-> latest ( 'published_at' )
-> limit ( 10 )
-> get ();
// Iterate over collection
foreach ( $publishedPosts as $post ) {
echo "{ $post -> title } - { $post -> published_at } \n " ;
}
// Get draft posts
$drafts = Post :: query ()
-> where ( 'status' , '=' , 'draft' )
-> where ( 'user_id' , '=' , $userId )
-> orderBy ( 'created_at' , 'DESC' )
-> get ();
// Count posts
$totalPosts = Post :: query () -> count ();
$publishedCount = Post :: query ()
-> where ( 'status' , '=' , 'published' )
-> count ();
// Delete old drafts
Post :: query ()
-> where ( 'status' , '=' , 'draft' )
-> where ( 'created_at' , '<' , date ( 'Y-m-d' , strtotime ( '-30 days' )))
-> delete ();
Best Practices
Use Mass Assignment Protection
Always define $fillable to protect against mass-assignment vulnerabilities: protected array $fillable = [ 'name' , 'email' , 'status' ];
Hide Sensitive Data
Use $hidden to exclude sensitive attributes from arrays and JSON: protected array $hidden = [ 'password' , 'api_token' ];
Use Type Casting
Cast attributes to appropriate types for better type safety: protected array $casts = [
'id' => 'int' ,
'active' => 'bool' ,
'options' => 'array'
];
Enable Timestamps
Let Eloquent manage timestamps automatically: protected bool $timestamps = true ;
Next Steps
Relationships Define relationships between your models
Query Builder Learn more about the underlying Query Builder