Models Architecture
Introduction
In the MVC pattern, models are responsible for managing data, business rules, and communication with the database. In Lacelium, models follow the Active Record design pattern, powered by an integrated Eloquent ORM abstraction. Each database table has a corresponding "Model" class that is used to interact with that table.
Defining Models
All application models reside in the app/Models directory. You can quickly generate a new model using the Dipper console:
php console make:model User
By default, models extend Lacelium\Core\Model (or Illuminate\Database\Eloquent\Model):
<?php
declare(strict_types=1);
namespace App\Models;
use Lacelium\Core\Model;
class Task extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'tasks';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'title',
'description',
'is_completed',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'is_completed' => 'boolean',
];
}
Model Conventions
Models in Lacelium adhere to several sensible conventions that reduce boilerplate configuration:
Table Names
Unless explicitly specified via the $table property, Lacelium uses the snake_case, plural name of the class as the table name. For example, a FlightCheck model will assume a table name of flight_checks.
Primary Keys
Lacelium assumes each table has a primary key column named id. If you wish to use a different primary key or UUID column, define a protected $primaryKey property:
protected $primaryKey = 'task_id';
public $incrementing = false;
protected $keyType = 'string';
Timestamps
By default, Lacelium expects created_at and updated_at timestamp columns to exist on your tables. The framework automatically sets their values when models are created or saved. To disable this behavior:
public $timestamps = false;
Declarative Column Casts ($boolean, $integer, etc.)
In addition to or in place of the monolithic $casts array, Lacelium models allow you to define declarative typed properties such as $boolean, $integer (or $interger), $float, $decimal, $string, $array, $datetime, and more:
class Product extends BaseModel
{
// Lists of columns to cast automatically
protected $boolean = ['is_active', 'is_featured'];
protected $interger = ['stock_count', 'views']; // supports $integer or $interger
protected $float = ['rating'];
protected $decimal = ['price' => 4, 'tax']; // custom precision or default 2 decimals
protected $string = 'sku, barcode'; // supports array or comma-separated string
protected $array = ['metadata', 'tags'];
protected $datetime = ['published_at'];
}
These typed properties are automatically merged with standard $casts with zero performance penalty and provide helper methods like $model->getBooleanColumns(), $model->getIntegerColumns(), and $model->getDecimalColumns().
Basic CRUD Operations
Once you have created a model and its associated database table, you are ready to start retrieving and persisting data.
Retrieving Models
You can retrieve all records from a table using the all() method or find a record by primary key with find():
use App\Models\Task;
// Retrieve all tasks
$tasks = Task::all();
// Retrieve a single task by ID
$task = Task::find(1);
// Retrieve or throw an exception if not found
$task = Task::findOrFail(1);
Inserting & Updating
To create a new record, instantiate a model instance, set its attributes, and call the save() method:
$task = new Task();
$task->title = 'Prepare release notes';
$task->is_completed = false;
$task->save();
Alternatively, you can use the static create() method, which utilizes mass assignment:
$task = Task::create([
'title' => 'Setup continuous deployment',
'is_completed' => false,
]);
Deleting Models
To delete a model, call the delete() method on the instance:
$task = Task::find(1);
$task->delete();
// Or delete by primary key directly
Task::destroy(1);
Task::destroy([1, 2, 3]);
Validation & Metadata
While models represent the data structure, validation is best handled via Form Requests or controller validation helpers before data reaches the model:
$data = $request->validate([
'title' => 'required|string|max:255',
'user_id' => 'required|integer|exists:users,id',
]);
$task = Task::create($data);
Next Steps
- Learn about advanced queries with the Query Builder.
- Discover model relationships in Eloquent Relationships.
- Manage your database schema with Migrations.