Persistence

Database Model

Table-oriented persistence base class with CRUD helpers, scopes, callbacks, timestamps and soft deletes.

Purpose

Model is an abstract base for table-oriented persistence. It wraps DatabaseDriverInterface, builds QueryBuilder instances for the configured table and provides common read/write helpers. It is framework infrastructure, not a requirement for every persistence use case.

Model definition

A concrete model defines table name, primary key and optionally allowed fields, timestamps, user tracking, soft deletes, scopes and callbacks.

use Lemonade\Framework\Database\Model;
use Lemonade\Framework\Database\QueryBuilder;

final class ArticleModel extends Model
{
    protected string $table = 'articles';
    protected string $primaryKey = 'id';

    protected array $allowedFields = [
        'title',
        'slug',
        'body',
        'published',
    ];

    protected bool $useTimestamps = true;
    protected bool $useSoftDeletes = true;

    protected function scopePublished(QueryBuilder $builder): QueryBuilder
    {
        return $builder->where('published', 1);
    }
}

Read helpers

Read APIs include all(), find(), first(), where(), exists(), countAll(), countWhere(), findMany(), cursor(), chunk(), builder(), query(), scoped() and applyScope(). Soft delete scope is applied automatically when enabled unless withDeleted() or onlyDeleted() is used.

$article = $articles->find($id);
$published = $articles->scoped('published')
    ->orderBy('created_at', 'DESC')
    ->getArray();

foreach ($articles->cursor() as $row) {
    // Stream rows.
}

Write helpers

Write APIs include save(), insert(), update(), insertBatch(), updateBatch(), delete(), forceDelete(), deleteWhere(), restore(), restoreWhere(), increment(), decrement(), firstOrCreate(), updateOrCreate(), upsert() and batchUpsert(). Insert returns the generated id, null when nothing was inserted, or 0 when the driver reports success without an insert id.

$id = $articles->insert([
    'title' => 'Hello',
    'slug' => 'hello',
    'body' => 'Article body',
    'published' => 1,
]);

$articles->update($id, [
    'title' => 'Updated title',
]);

Allowed fields

allowedFields filters insert/update payloads. Timestamp, user tracking and soft delete columns are added to the allowed list automatically when their features are enabled.

Callbacks

When allowCallbacks is true, model events can call protected methods listed in beforeInsert, afterInsert, beforeUpdate, afterUpdate, beforeInsertBatch, afterInsertBatch, beforeUpdateBatch, afterUpdateBatch, beforeFind, afterFind, beforeDelete and afterDelete. Callback payloads are associative arrays and may return a modified payload.

Usage boundary

Controllers should usually depend on application services. Those services may use Model for straightforward table persistence, QueryBuilder for read models or Database for custom SQL. Model is not a replacement for domain logic.