Models & Lifecycle
Rubik Models are the heart of your application. They handle data transport, persistence, and business logic events.
Dirty State Tracking
Rubik employs an intelligent "Dirty Checking" mechanism.
- When a model is fetched (
find,all), it is considered "clean". - When you modify a property (
$user->name = 'New'), the model marks that specific field as dirty in$_dirty. - When
save()orupdate()is called, only the dirty fields are included in theUPDATESQL statement.
Benefit: This prevents overwriting data changed by other processes and reduces query size.
The save() Method
The save() method is smart. It determines whether to INSERT or UPDATE based on the internal $exists boolean property.
$user = new User();
$user->save(); // Performs INSERT, sets $exists = true
$user->name = "Changed";
$user->save(); // Performs UPDATE on ID
Ignore Mode
You can pass true to save() to perform an "Insert Ignore".
- MySQL:
INSERT IGNORE INTO... - SQLite:
INSERT OR IGNORE INTO...
Batch Operations
insertMany
Inserts multiple arrays of raw data. This bypasses Model events and setters for performance.
User::insertMany([
['name' => 'A', 'email' => 'a@a.com'],
['name' => 'B', 'email' => 'b@b.com'],
]);
ID Retrieval
insertMany attempts to return the inserted IDs. However, due to limitations in SQLite and MySQL < 8.0.22, batch inserts do not reliably return all generated Auto-Increment IDs.
Lifecycle Hooks
Rubik fires protected methods during the model's lifecycle. Override these in your model to add logic (e.g., Hashing passwords, UUID generation).
| Hook | Trigger Point |
|---|---|
beforeCreate |
Before an INSERT query. |
afterCreate |
After a successful INSERT. |
beforeUpdate |
Before an UPDATE query. |
afterUpdate |
After a successful UPDATE. |
beforeSave |
Runs before both Create and Update. |
afterSave |
Runs after both Create and Update. |
beforeDelete |
Before DELETE query. |
afterDelete |
After a successful DELETE. |
Example: Auto-hashing Password
class User extends Model {
protected function beforeSave(): void {
if (isset($this->_dirty['password'])) {
$this->password = password_hash($this->password, PASSWORD_BCRYPT);
}
}
}
Serialization
Models implement JsonSerializable. When you json_encode($model), it automatically calls toArray(), which returns the internal $_data array.