VOOZH about

URL: https://deepwiki.com/mathsgod/light/6.3-revision-system

⇱ Revision System | mathsgod/light | DeepWiki


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

Revision System

Purpose and Scope

The revision system provides automatic, comprehensive change tracking for all models in the Light framework. Every insert, update, and delete operation is captured with complete before/after state snapshots, enabling full audit trails and the ability to restore previous field values.

This document covers the automatic tracking mechanism, the EventLog data structure, and the GraphQL API for querying and restoring revisions. For information about the base model class that enables this system, see Base Model Class (Light\Model). For details on automatic timestamp and user tracking, see Auto-Auditing and Lifecycle Hooks.


EventLog Data Model

The revision system stores all changes in the EventLog table, which serves as the permanent audit trail. Each record captures a single state transition.

FieldTypeDescription
eventlog_idINTPrimary key, auto-increment
classVARCHARFully qualified class name of the model (e.g., Light\Model\User)
idINTPrimary key value of the affected model instance
actionENUMOne of: Insert, Update, Delete
sourceJSONState before the change (NULL for inserts)
targetJSONState after the change (NULL for future use)
user_idINTUser who performed the action (foreign key with SET NULL ON DELETE)
created_timeDATETIMETimestamp when the change occurred

The user_id foreign key uses SET NULL ON DELETE to preserve audit history even when user accounts are deleted. This ensures that historical records remain intact while indicating the performing user is no longer available.

Sources: src/Model.php131-139 src/Model.php227-235


Change Capture Mechanism

Changes are automatically captured through lifecycle hooks in the Light\Model base class. The system distinguishes between three types of operations:

Insert Operations

When a new model instance is saved for the first time:

  • action is set to "Insert"
  • source is set to null (no previous state exists)
  • target contains the complete JSON-serialized state of the new record
  • created_time and created_by fields are automatically populated

Update Operations

When an existing model instance is modified:

  • action is set to "Update"
  • source contains the JSON-serialized state before the update
  • target contains the JSON-serialized state after the update
  • updated_time and updated_by fields are automatically populated
  • The previous state is retrieved via static::get($this->$key) before saving

Delete Operations

When a model instance is deleted:

  • action is set to "Delete"
  • source is set to null
  • target contains the final JSON-serialized state before deletion
  • The EventLog entry is inserted before the actual deletion occurs

Sources: src/Model.php144-238 src/Model.php120-142


Revision Tracking Flow


Sources: src/Model.php144-238 src/Model.php120-142


Source and Target Snapshots

The revision system captures state snapshots as JSON-encoded objects in the source and target fields:

Source Field

Contains the state before the operation:

  • Insert: null (no previous state)
  • Update: Complete previous state of the model
  • Delete: null (not used)

Target Field

Contains the state after the operation:

  • Insert: Complete new state of the model
  • Update: Complete modified state of the model
  • Delete: Final state before deletion

Blob Field Exclusion

Binary large object (BLOB) fields are automatically excluded from revision tracking to prevent performance degradation and excessive storage consumption. The system filters out fields with data types longblob, mediumblob, and tinyblob before JSON serialization.


The Util::Sanitize() method ensures that the JSON encoding removes any sensitive or non-serializable data before storage.

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


GraphQL API for Revision Queries

The RevisionController provides GraphQL queries and mutations for interacting with the revision system:

Query: getRevisionsByModel

Retrieves the complete revision history for a specific model instance:


Parameters:

  • model_class (string): Fully qualified class name
  • model_id (int): Primary key value of the model instance

Returns: Array of Revision objects sorted by created_time in descending order

Required Permission: revision.read

Sources: src/Controller/RevisionController.php29-42

Revision Type Fields

The Light\Type\Revision GraphQL type wraps an EventLog entry and provides computed fields:

FieldTypeDescription
revision_idIntThe EventLog primary key (eventlog_id)
createdTimeStringTimestamp of the change
revisionByStringName of the user who made the change (null if user deleted)
contentMixedThe source state (sorted by key)
deltaMixedOnly the fields that changed between source and target
diffMixedUnified diff format showing line-by-line changes

Delta Calculation

The getDelta() method compares the source and target snapshots to identify only the changed fields:


Unified Diff Generation

The getDiff() method uses the SebastianBergmann\Diff library to generate human-readable unified diffs for each changed field, similar to Git diff output.

Sources: src/Type/Revision.php21-70 src/Type/Revision.php72-87 src/Type/Revision.php89-118


Restoring Previous States

The revision system supports selective field restoration, allowing administrators to revert specific fields without affecting the entire record.

Mutation: restoreRevision


Parameters:

  • revision_id (int): The EventLog ID containing the desired previous state
  • fields (string[]): Array of field names to restore

Behavior:

  1. Retrieves the EventLog entry by revision_id
  2. Loads the current model instance by class name and primary key
  3. For each field in the fields array:
    • Validates that the field exists in the model's schema
    • Sets the field value from the revision's content (source)
  4. Saves the model, triggering a new EventLog entry for the restoration

Required Permission: revision.restore

Sources: src/Controller/RevisionController.php15-25 src/Type/Revision.php27-43

Restoration Flow Diagram


Sources: src/Controller/RevisionController.php15-25 src/Type/Revision.php27-43


Controlling Revision Logging

The Light\Model class provides static flags to control which operations are logged for each model subclass:


Model classes can override these flags to disable logging for specific operations. For example, to disable update logging for a high-frequency model:


The logging condition is checked at src/Model.php221-225:


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


User Context Extraction

The revision system automatically captures the performing user's ID from the authenticated session. The process uses the dependency injection container:


Null Safety: If no authenticated user exists (e.g., system operations, CLI scripts), user_id is set to null. The EventLog.user_id column accepts nulls, and the GraphQL revisionBy field returns null when the user cannot be determined.

User Deletion Handling: The foreign key constraint uses SET NULL ON DELETE, ensuring that when a user account is deleted, their historical audit entries remain intact but show user_id as null. The Light\Type\Revision::getRevisionBy() method gracefully handles this by returning null when the user no longer exists.

Sources: src/Model.php125-129 src/Model.php146-151 src/Type/Revision.php51-61


Integration with Auto-Auditing

The revision system is tightly integrated with the auto-auditing features documented in Auto-Auditing and Lifecycle Hooks:

  • created_time/created_by: Set during insert operations before logging
  • updated_time/updated_by: Set during update operations before logging
  • Both the auditing fields and the revision snapshot are captured in the same transaction

This ensures consistency between the model's audit fields and the EventLog entries.

Sources: src/Model.php156-169