-
Notifications
You must be signed in to change notification settings - Fork 0
entity
An entity is a PHP object representing a single database row. Extend AbstractEntity, declare your columns and types in $casts, and the library handles all type conversion — both when reading from the database and when writing back to it.
<?php
use WPTechnix\WPModels\AbstractEntity;
class ProductEntity extends AbstractEntity
{
protected static string $primaryKey = 'id';
protected static array $casts = [
'id' => 'int',
'name' => 'string',
'price' => 'decimal',
'stock' => 'int',
'is_active' => 'bool',
'tags' => 'json',
'status' => 'enum:ProductStatus',
'published_at' => 'datetime',
'created_at' => 'datetime',
];
}Every column you want to access or write must appear in $casts. Accessing an undeclared column throws a LogicException.
The column that holds the row's unique identifier. Defaults to 'id'. Must also appear in $casts.
| Cast | PHP type on read | Database storage |
|---|---|---|
int |
int |
integer |
float |
float |
float / double |
decimal |
string |
DECIMAL or VARCHAR
|
string |
string |
any text column |
bool |
bool |
0 or 1 (TINYINT) |
datetime |
DateTimeImmutable |
UTC datetime string |
json |
array |
JSON-encoded string |
enum:ClassName |
BackedEnum |
enum's backing value |
Use decimal for money and any value where precision matters. It is stored and returned as a PHP string ('9.99', not 9.99), which avoids floating-point rounding errors.
Use float for non-financial numerics where native float precision is acceptable.
Datetime values follow a consistent four-step cycle so you never have to manage timezone conversion yourself:
-
Stored in the database as a UTC string (
2024-06-15 14:00:00) -
Hydrated into a
DateTimeImmutableobject set to UTC -
Read via
__getwith automatic conversion to the WordPress site timezone (Settings → General → Timezone) - Saved converted back to UTC before writing to the database
// Reading — always returns a DateTimeImmutable in your WordPress timezone
echo $product->published_at->format('d M Y, H:i'); // e.g. "15 Jun 2024, 16:00" on a UTC+2 site
// Writing — pass any DateTimeInterface; it will be stored as UTC
$product->published_at = new DateTimeImmutable('now');
$product->save();PHP 8.1 backed enums are supported natively. Define your enum with a string or integer backing type, then reference it in $casts using enum:FullyQualifiedClassName:
enum ProductStatus: string
{
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}protected static array $casts = [
'status' => 'enum:ProductStatus',
// ...
];$product->status; // ProductStatus::Draft
$product->status = ProductStatus::Published;
$product->save(); // stores 'published' in the database
if ($product->status === ProductStatus::Published) {
// ...
}Access typed values directly by column name using standard property syntax:
$product = ProductModel::instance()->find(1);
$product->id; // int
$product->name; // string
$product->price; // string '9.99'
$product->is_active; // bool
$product->tags; // array
$product->created_at; // DateTimeImmutable (WP timezone)Explicit accessors are also available:
$product->getAttribute('name'); // same as $product->name
$product->getAttributes(); // all typed attributes as an arrayAssign values using standard property syntax. The cast is applied on assignment and changes are held in memory until you call save():
$product->name = 'Wireless Keyboard';
$product->price = '39.99';
$product->is_active = true;
// Explicit form
$product->setAttribute('name', 'Wireless Keyboard');After a row is fetched from the database, the entity tracks which properties have been changed:
$product = ProductModel::instance()->find(1);
$product->isDirty(); // false
$product->name = 'New Name';
$product->isDirty(); // true
$product->isAttributeDirty('name'); // true
$product->isAttributeDirty('price'); // false
$product->getOriginal('name'); // original DB value: 'Old Name'save() includes only dirty attributes in the SQL UPDATE, so unchanged columns are never touched.
Persists all dirty attributes to the database. Returns true on success.
- If the entity was fetched from the database,
save()runs anUPDATE. - If the entity was constructed without a primary key value (see below),
save()runs anINSERTand sets the primary key on the object.
// Updating an existing row
$product->name = 'Updated Name';
$product->price = '49.99';
$product->save();
// Inserting a new row
$product = new ProductEntity();
$product->name = 'Brand New Product';
$product->price = '29.99';
$product->save();
echo $product->id; // set after insertNote:
save()requires the entity to be linked to its model. Entities fetched through a model are linked automatically. When constructing an entity manually withnew, call$product->save()only afterProductEntity::create()has associated it with the model, or useProductModel::instance()->create($data)instead, which is the more straightforward approach for most cases.
Removes the row from the database. After deletion, exists() returns false.
$product->delete();
$product->exists(); // false$product->isNew(); // true if no primary key is set (never persisted)
$product->exists(); // checks the in-memory primary key value
$product->exists(forceCheckInDb: true); // always queries the databaseReloads the entity's attributes from the database, discarding any local changes:
$product->refresh();$product->toArray(); // ['id' => 1, 'name' => '...', ...]
json_encode($product); // same output via JsonSerializableSerialisation rules:
-
datetime— ISO-8601 string -
enum— the enum's backing string or integer value -
json— the decoded array (not re-encoded)
Cloning creates an independent copy of the entity with its primary key cleared, marking it as new. Useful for creating a new row based on an existing one:
$copy = clone $product;
$copy->isNew(); // true
$copy->name = 'Copy of ' . $product->name;
$copy->save(); // inserts a new rowIf you need the model instance from within an entity:
$model = $product->getModel(); // ProductModel
$model->find(2);