Overview
Models are PHP classes that represent database tables and provide methods for creating, reading, updating, and deleting records (CRUD operations).
Defining Models
Basic Model
Extend the Aeros\Src\Classes\Model base class:
namespace App\Models ;
use Aeros\Src\Classes\ Model ;
class User extends Model
{
protected $table = 'users' ;
protected $primary = 'id' ;
protected $fillable = [ 'name' , 'email' , 'status' ];
}
Model Properties
The database table name. Auto-detected from class name if not set.
The primary key column name.
Columns that can be mass-assigned (for security).
Columns that are protected from mass-assignment.
Auto-Detected Table Names
If $table is not defined, the model automatically uses the pluralized, lowercase class name:
class User extends Model { } // → users
class Post extends Model { } // → posts
class Category extends Model { } // → categories
Creating Records
Create Single Record
$user = User :: create ([
'name' => 'John Doe' ,
'email' => '[email protected] ' ,
'status' => 'active'
]);
echo $user -> id ; // Auto-generated ID
Create Multiple Records
Finding Records
Find by ID
// Find user with id = 1
$user = User :: find ( 1 );
// Returns User model or null
if ( $user ) {
echo $user -> name ;
}
Find by Conditions
// Single condition (key = value)
$user = User :: find ([
[ 'email' , '[email protected] ' ]
]);
// Multiple conditions with operators
$users = User :: find ([
[ 'status' , '=' , 'active' ],
[ 'role' , '=' , 'admin' ]
]);
// With OR conditions
$users = User :: find ([
[ 'status' , '=' , 'active' , 'OR' ],
[ 'status' , '=' , 'pending' , 'OR' ],
[ 'status' , '=' , 'verified' ]
]);
Find with Specific Columns
// Only fetch id, name, email
$user = User :: find ( 1 , [ 'id' , 'name' , 'email' ]);
The find() method supports multiple condition formats:
// Format 1: [column, value]
[ 'email' , '[email protected] ' ] // WHERE email = ?
// Format 2: [column, operator, value]
[ 'age' , '>' , 18 ] // WHERE age > ?
// Format 3: [column, operator, value, logical]
[ 'status' , '=' , 'active' , 'OR' ] // WHERE status = ? OR
// Format 4: Associative array
[[ 'status' => 'active' ]] // WHERE status = ?
Updating Records
Update by Instance
$user = User :: find ( 1 );
$user -> name = 'Jane Doe' ;
$user -> email = '[email protected] ' ;
$user -> save ();
Update with Method
// Update specific records
User :: update (
[ 'status' => 'inactive' ], // New values
[[ 'role' , '=' , 'guest' ]] // WHERE conditions
) -> commit ();
Update and Commit
Changes are staged until commit() is called:
$user = User :: find ( 1 );
$user -> status = 'verified' ;
$result = $user -> save (); // Calls commit() internally
Deleting Records
Delete Instance
$user = User :: find ( 1 );
$user -> delete () -> commit ();
Delete by Condition
// Delete all inactive users
User :: delete ([
[ 'status' , '=' , 'inactive' ]
]) -> commit ();
Property Access
Getting Values
$user = User :: find ( 1 );
echo $user -> id ;
echo $user -> name ;
echo $user -> email ;
Setting Values
$user = User :: find ( 1 );
// Set individual properties
$user -> name = 'New Name' ;
$user -> email = '[email protected] ' ;
// Save changes
$user -> save ();
Protected Properties
Primary keys and guarded properties cannot be updated
class User extends Model
{
protected $primary = 'id' ;
protected $guarded = [ 'role' , 'permissions' ];
}
$user = User :: find ( 1 );
// ❌ Throws InvalidArgumentException
$user -> id = 999 ;
// ❌ Throws InvalidArgumentException
$user -> role = 'admin' ;
Fillable vs Guarded
Using Fillable (Whitelist)
class User extends Model
{
protected $fillable = [ 'name' , 'email' , 'bio' ];
}
// ✅ Only name, email, bio can be set
User :: create ([
'name' => 'John' ,
'email' => '[email protected] ' ,
'bio' => 'Developer' ,
'role' => 'admin' // Ignored (not in fillable)
]);
Using Guarded (Blacklist)
class User extends Model
{
protected $guarded = [ 'role' , 'permissions' ];
}
// ✅ All columns except role and permissions can be set
User :: create ([
'name' => 'John' ,
'email' => '[email protected] ' ,
'role' => 'admin' // Ignored (in guarded)
]);
Eager Loading
Prevent N+1 query problems by eager loading relationships:
// Load user with their plans
$user = User :: with ( 'plans' ) -> find ( 1 );
// Access relationship without additional query
foreach ( $user -> plans as $plan ) {
echo $plan -> name ;
}
// Load multiple relationships
$user = User :: with ([ 'plans' , 'profile' , 'roles' ]) -> find ( 1 );
See Relationships for more details.
Model Methods
Instance Methods
Save changes to the current model instance $user -> name = 'Updated' ;
$user -> save ();
Commit pending INSERT, UPDATE, or DELETE operations $user -> delete () -> commit ();
Get the table name for this model echo $user -> getTableNameFromModel (); // 'users'
Get the primary key column name echo $user -> getPrimaryKey (); // 'id'
Static Methods
Find records by ID or conditions User :: find ( 1 );
User :: find ([[ 'status' , 'active' ]]);
Create a new record User :: create ([ 'name' => 'John' ]);
Create multiple records at once
Update records matching conditions User :: update ([ 'status' => 'active' ], [[ 'role' , 'user' ]]);
Delete records matching conditions User :: delete ([[ 'status' , 'inactive' ]]);
Eager load relationships User :: with ( 'plans' ) -> find ( 1 );
Error Handling
Invalid Property
$user = User :: find ( 1 );
try {
echo $user -> nonexistent ;
} catch ( InvalidArgumentException $e ) {
// Property "nonexistent" is not mapped to any column on "users" table
}
Primary Key Update
try {
$user -> id = 999 ;
} catch ( InvalidArgumentException $e ) {
// Primary key "id" cannot be updated
}
Unknown Column
try {
$user -> unknown_field = 'value' ;
} catch ( InvalidArgumentException $e ) {
// Property "unknown_field" is not mapped to any column on "users" table
}
Advanced Usage
Custom Table Name
class User extends Model
{
protected $table = 'app_users' ; // Use custom table name
}
Custom Primary Key
class User extends Model
{
protected $primary = 'user_id' ; // Use custom primary key
}
Combining with Query Builder
$users = User :: query ()
-> where ( 'status' , 'active' )
-> orderBy ( 'created_at' , 'DESC' )
-> limit ( 10 )
-> get ();
See Query Builder for more details.
Best Practices
Always define fillable or guarded to prevent mass-assignment vulnerabilities
Use eager loading to avoid N+1 query problems
Validate data before creating or updating records
Use transactions for operations that modify multiple tables
Never trust user input - always validate and sanitize
Next Steps
Relationships Define relationships between models
Query Builder Build complex database queries