VOOZH about

URL: https://deepwiki.com/mathsgod/light/6.1-base-model-class-(lightmodel)

⇱ Base Model Class (Light\Model) | mathsgod/light | DeepWiki


Loading...
Last indexed: 31 January 2026 (cf9511)
Menu

Base Model Class (Light\Model)

Purpose and Scope

The Light\Model class serves as the base class for all domain models in the Light framework. It extends Light\Db\Model to provide automatic audit tracking, GraphQL field exposure, and permission checking capabilities. Every model that requires change tracking, user attribution, or GraphQL API exposure should inherit from this class.

This document covers the base class structure and core functionality. For details on automatic timestamp/user tracking and lifecycle hooks, see Auto-Auditing and Lifecycle Hooks. For revision history and state snapshots, see Revision System. For specific model implementations, see Core Database Models.

Class Hierarchy and Relationships


Sources: src/Model.php1-239

The Light\Model class at src/Model.php14 declares abstract class Model extends \Light\Db\Model, establishing the inheritance hierarchy. The class maintains a static reference to the dependency injection container at src/Model.php19 (static $container), which it uses to access the Auth\Service for determining the current user during save and delete operations.

Core Functionality

Field Introspection


Sources: src/Model.php21-26

The __fields() method at src/Model.php21-26 provides runtime field introspection by querying table metadata:


This method returns an array of all column names for the model's database table. It is used internally by bind() for data assignment validation and by the revision system for field filtering.

Data Binding

The bind() method at src/Model.php28-39 provides safe mass assignment by filtering input data against the model's actual fields:

StepLogicPurpose
1if ($v === null) continue;Skip null values
2if (!in_array($k, $fields)) continue;Ignore non-existent fields
3$this->$k = $v;Assign validated data

This prevents accidental assignment of non-column data and protects against mass assignment vulnerabilities.

Sources: src/Model.php28-39

GraphQL Field Exposure


Sources: src/Model.php42-117

The base model exposes audit metadata through GraphQL fields using the #[Field] attribute:

Timestamp Fields:

User Attribution Fields:

  • createdBy() at src/Model.php47-55 - Looks up User::Get($this->created_by) and returns the user's name
  • updatedBy() at src/Model.php62-70 - Looks up User::Get($this->updated_by) and returns the user's name

These methods return empty strings if the user no longer exists, ensuring GraphQL queries don't fail when referenced users are deleted.

Permission Methods

The base class provides three permission checking methods with #[Field] and #[InjectUser] annotations:

MethodLocationDefault BehaviorPurpose
canDelete()src/Model.php74-77Returns trueOverride to implement deletion authorization
canUpdate()src/Model.php85-97Returns trueOverride to implement update authorization
canView()src/Model.php100-117Returns trueOverride to implement read authorization

The commented code at src/Model.php87-95 and src/Model.php102-113 shows the intended pattern for RBAC integration:


This allows subclasses to implement row-level permissions by checking if the current user has rights to the specific model instance.

Sources: src/Model.php74-117

Automatic Audit Tracking

Save Lifecycle


Sources: src/Model.php144-238

The save() method at src/Model.php144-238 implements a sophisticated audit trail system:

Phase 1: User Context Extraction src/Model.php146-151

  • Retrieves the DI container from self::$container
  • Extracts the Auth\Service instance
  • Obtains the current user ID via getUser()?->user_id

Phase 2: Operation Detection src/Model.php153-170

  • If primary key is empty: Insert operation
    • Sets created_time to current timestamp
    • Sets created_by to current user ID
  • If primary key exists: Update operation
    • Sets updated_time to current timestamp
    • Sets updated_by to current user ID

Phase 3: State Capture src/Model.php172-217

For updates src/Model.php172-212:

  1. Loads current state from database: $source = static::get($this->$key)
  2. Filters blob fields (longblob, mediumblob, tinyblob) from source to avoid memory issues src/Model.php176-185
  3. Serializes filtered source: json_encode(Util::Sanitize($source->jsonSerialize()))
  4. Filters blob fields from target state src/Model.php201-209
  5. Serializes filtered target: json_encode(Util::Sanitize($target))

For inserts src/Model.php214-217:

  1. Sets source = null
  2. Serializes current state as target

Phase 4: Persistence src/Model.php219

  • Calls parent::save() to execute the actual database operation

Phase 5: Audit Logging src/Model.php221-236

  • Checks static flags: $_log_insert, $_log_update, $_log_delete
  • Inserts audit record into EventLog with columns: class, id, action, source, target, user_id, created_time

Delete Lifecycle


Sources: src/Model.php120-142

The delete() method at src/Model.php120-142 captures the complete model state before deletion:

  1. Get primary key src/Model.php122: $key = $this->_key()
  2. Extract user context src/Model.php124-129: Same pattern as save()
  3. Log deletion event src/Model.php131-139:
    • action = "Delete"
    • source = null (no previous state for deletion)
    • target = complete serialized state before deletion
    • user_id = current user
  4. Execute deletion src/Model.php141: return parent::delete()

This ensures the state is captured before the record is removed from the database, allowing restoration via the revision system (see RevisionController).

Static Configuration

Logging Control Flags


Sources: src/Model.php16-18 src/Model.php221-236

Three static boolean properties control EventLog insertion:

PropertyDefaultControlsLocation
$_log_inserttrueInsert operation loggingsrc/Model.php16
$_log_deletetrueDelete operation loggingsrc/Model.php17
$_log_updatetrueUpdate operation loggingsrc/Model.php18

These flags are checked at src/Model.php221-225:


Subclasses can override these to disable audit logging for specific models:


Container Integration

The static container property and setter enable dependency injection:

ComponentLocationPurpose
static $containersrc/Model.php19Stores DI container reference
SetContainer($container)src/Model.php79-82Static setter for container

The container is accessed during save() src/Model.php147 and delete() src/Model.php125 to retrieve the Auth\Service:


The container must be set via Model::SetContainer() during application bootstrap (typically in Light\App initialization) to enable user attribution.

Sources: src/Model.php19 src/Model.php79-82 src/Model.php125-129 src/Model.php146-151

Integration with Related Systems

EventLog and Revision System

Every mutation tracked by Light\Model creates an EventLog record with the following structure:

FieldTypePurposeExample
classstringFully-qualified model class"Light\Model\User"
idmixedPrimary key value42
actionstringOperation type"Insert", "Update", "Delete"
sourceJSONState before change (null for insert/delete){"name":"Old"}
targetJSONState after change{"name":"New"}
user_idintActor's user ID (nullable)7
created_timetimestampWhen the action occurred"2024-01-15 14:30:00"

The RevisionController at src/Controller/RevisionController.php12-43 queries these logs:

The restoration process at src/Type/Revision.php27-43 uses __fields() to validate that restored fields exist on the target model before assignment.

Sources: src/Model.php131-139 src/Model.php227-235 src/Controller/RevisionController.php1-43 src/Type/Revision.php27-43

GraphQL Type Mapping

The Light\Model base class is designed for seamless GraphQL integration via GraphQLite annotations. All subclasses automatically inherit:

  1. Audit metadata fields: createdTime, createdBy, updatedTime, updatedBy
  2. Permission fields: canDelete, canUpdate, canView

These fields are exposed in the GraphQL schema without additional configuration. Domain models only need to add the #[Type] annotation and any domain-specific #[Field] methods.

Example inheritance in practice:


Sources: src/Model.php42-117

Blob Field Handling

The save operation includes special handling for blob columns to prevent memory exhaustion when storing large binary data in revision history. At src/Model.php176-185 and src/Model.php201-209 the code filters out blob fields:


This ensures that EventLog records don't duplicate large binary data, while still tracking changes to other fields. Models with blob columns still benefit from audit tracking for their non-binary fields.

Sources: src/Model.php176-185 src/Model.php201-209