⬡ Lacelium
⌘K
Version 2.x ▾

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