Entity
About 3 min
Overview
The Entity class is the core component of the DataForge design, encapsulating the business logic of a module. Developers extend the DataForge\Entity
base class to define module-specific logic. This design promotes reusability, modularity, and efficiency by encapsulating module-specific queries and relationships within a single entity class.
All entity class files must be created in the following directory:
app/DataForge/Entity
Class Structure
namespace App\DataForge\Entity;
use DataForge\Entity;
class Property extends Entity
{
}
Methods
1. init($args)
(Abstract Method)
- Purpose: This method is mandatory in all extended entity classes.
- Description: It loads the entity base properties with the provided arguments.
- Functionality:
- Called during entity instantiation.
- Accepts parameters (e.g., integer, string, array) passed during instantiation.
- Developers use this method to query data (using SQL classes) based on the input arguments and bind the returned data as base properties of the entity.
- If no data is returned, the entity is not instantiated, and an error is raised.
- Example:
function init($id)
{
return \Sql('Property:list', ['id' => $id, 'select' => 'entity'])->fetchRow();
}
- Key Points:
- SQL class and method mapping is handled directly via the
\Sql
helper function. - This approach eliminates the need for configuration files or dependency injection, focusing on performance and simplicity.
- SQL class and method mapping is handled directly via the
2. access()
(Optional Method)
- Purpose: Defines access validation logic.
- Description: Developers write custom access checks inside this function, which returns true or false.
- Functionality:
- Automatically called after
init()
. - Implements custom business rules for access validation based on the logged-in user.
- Returns a boolean value (true or false).
- If false is returned, the entity instantiation is halted, and an error is raised.
- Automatically called after
- Example:
function access()
{
return \Sql('Property:access', ['id' => $this->id, 'user_id' => Auth::userId()])->fetchColumn();
}
3. Attrib/Property Methods
- Purpose: Defines entity attributes as methods, allowing dynamic, lazy-loaded properties.
- Description:
- Entity attributes are defined as methods prefixed with "get".
- Supports lazy-loading by loading properties only when accessed.
- Methods can assign data directly, load from SQL methods, or build relationships with other entities.
- Example:
function getFullAddress()
{
return $this->address.', '.$this->suburb.' '.$this->state.' '.$this->postcode;
}
function getIncome()
{
return Sql('Property:income', ['id' => $this->id])->fetchColumn();
}
function getTenant()
{
return DataForge::getTenant($this->tenant_id);
}
Usage:
$property = DataForge::getProperty(12345);
print $property->FullAddress; // Calls `getFullAddress` and prints the full address.
print $property->Income; // Calls `getIncome` and prints the income.
print_r($property->Tenant); // Calls `getTenant` and prints the tenant entity.
4. attribGroups()
(Optional Method)
- Purpose: Defines collections of related attributes for an entity.
- Description:
- Groups related attributes into named collections.
- Simplifies bulk retrieval of multiple entity properties with a single call.
- Example:
function attribGroups()
{
return [
'Contacts' => 'AgencyContacts, OwnerContacts, TenantContacts',
'Summary' => 'Income, Expense, WithHold, Arrears'
];
}
Usage:
$propertySummary = $property->toArray('Summary');
// Returns ['Income', 'Expense', 'WithHold', 'Arrears']
Key Features
1. Lazy Loading
- Entity properties are only loaded when accessed, ensuring optimal performance.
- Once loaded, subsequent accesses return cached data from memory, avoiding redundant queries.
$income = $property->Income; // Calls `getIncome()` only on the first access.
2. Inter-Entity Connectivity
- Entities can be linked seamlessly, facilitating inter-module relationships without duplicating queries or code.
$tenant = $property->Tenant; // Access tenant entity properties directly.
3. Customizable Access Control
- Implement custom access checks within entity methods to secure sensitive data.
4. Attribute Collections
- Group and retrieve multiple entity attributes with minimal effort using
attribGroups()
andtoArray()
methods.
5. Single Inheritance
- Entities can inherit functionality from base classes, supporting shared logic and specialized extensions.
class Tenant extends User
{
function getProperty()
{
return DataForge::getProperty($this->property_id);
}
}
Advanced Example
Core Example: User Entity
namespace App\DataForge\Entity;
class User extends Entity
{
function init($args = null)
{
if (!$args) $args = Auth::id();
if (!is_array($args)) $args = ['id' => $args];
$args['select'] = 'entity';
return \Sql('User:list', $args)->fetchRow();
}
function getOrigin($id = null)
{
$tmp = $id ?? $this->parent_id;
if (!$tmp || $this->parent_id === 0) return $this->id;
$parent_id = \Sql('User:getUserParent', ['id' => $tmp])->fetchColumn();
return (!$parent_id || $parent_id == $tmp) ? $tmp : $this->getOrigin($parent_id);
}
function getPermissions()
{
return \Sql('User:permissions', ['id' => $this->id])->fetchRowList();
}
}
Extended Example: Tenant Entity
class Tenant extends User
{
function init($args = null)
{
$user = parent::init($args);
if (!$user) return false;
$tenant = \Sql('Tenant:leaseInfo', ['id' => $user['id']])->fetchRow();
if (!$tenant) return false;
return array_merge($user, $tenant);
}
function getProperty()
{
return DataForge::getProperty($this->property_id);
}
}
Usage:
$tenant = DataForge::getTenant(123); // Instantiate tenant entity by ID
$tenant = DataForge::getTenant(['email' => 'tenant@data-forge.tech']); // By email
echo $tenant->Property->address1; // Access tenant property address
Ideal Use Cases
- Small Applications: Quickly bootstrap functionality with compact, ready-to-use entities.
- Large Applications: Integrate seamlessly as a stable foundation for scalable systems.