Overview
BaseModel extends Laravel’s Eloquent Model with advanced features including:
- Validation: Built-in validation with scenario support (create/update)
- Hierarchy: Self-referencing tree structures with ancestor/descendant traversal
- Role-based field restrictions: Control field access per Spatie role
- Parent model support: Single Table Inheritance (STI) pattern
- MongoDB relations: Custom relation helpers for MongoDB connections
All models in your application should extend BaseModel to leverage these features.
Constants
MODEL
The name of the model used for array parameter wrapping.
Example:
class User extends BaseModel
{
const MODEL = 'user';
}
// Expects input: ['user' => ['name' => 'John', 'email' => '[email protected]']]
columns
Default columns for the model. Used for field selection in queries.
Example:
const columns = ['id', 'name', 'email', 'created_at'];
RELATIONS
Defines allowed relations that can be eager loaded via API requests.
Example:
const RELATIONS = ['posts', 'comments', 'roles'];
Only relations listed here can be loaded via the relations query parameter. This is a security feature.
PARENT
Defines parent class information for Single Table Inheritance hierarchy.
Example:
class Admin extends User
{
const PARENT = [
'class' => User::class
];
}
HIERARCHY_FIELD_ID
const HIERARCHY_FIELD_ID = null;
Field name for self-referencing hierarchy (e.g., parent_id, manager_id).
Example:
class Category extends BaseModel
{
const HIERARCHY_FIELD_ID = 'parent_id';
}
Properties
fieldsByRole
protected array $fieldsByRole = [];
Role-to-field restriction map. Declares which fields require specific Spatie roles to write.
fieldsByRole
array<string, list<string>>
default:"[]"
Maps role names to arrays of privileged field names
Example:
protected array $fieldsByRole = [
'superadmin' => ['is_superuser', 'permissions'],
'admin' => ['status', 'role_id', 'is_verified'],
];
Behavior:
- Fields NOT listed are writable by any authenticated user
- Superusers bypass all restrictions
- Multiple roles grant union of field access
scenario
protected string $scenario = 'create';
Current operation scenario (create or update). Used for context-aware validation.
fieldKeyUpdate
protected string|int|null $fieldKeyUpdate = null;
Reference column for update operations. Falls back to primary key when null.
Key Methods
getDeniedFieldsForUser()
public function getDeniedFieldsForUser(mixed $user): array
Returns fields the given user is NOT allowed to write.
The authenticated user model (must have Spatie’s hasRole() method)
Array of field names the user cannot write
Algorithm:
- If
$fieldsByRole is empty → return [] (no restrictions)
- If user has
is_superuser = true → return []
- Build universe of all privileged fields
- Build allowed set from user’s roles
- Return universe − allowed
Example:
$user = auth()->user();
$deniedFields = $model->getDeniedFieldsForUser($user);
// ['is_superuser', 'permissions'] if user lacks superadmin role
Accessor Methods
getPrimaryKey()
public function getPrimaryKey(): string
Returns the model’s primary key name.
getFieldKeyUpdate()
public function getFieldKeyUpdate(): string|int|null
Returns the field used for updates (defaults to primary key).
getScenario()
public function getScenario(): string
Returns current validation scenario (create or update).
setScenario()
public function setScenario(string $scenario): void
Sets the validation scenario.
Hierarchy Methods
hasHierarchy()
public function hasHierarchy(): bool
Checks if model uses Single Table Inheritance (has PARENT defined).
hasHierarchyField()
public function hasHierarchyField(): bool
Checks if model supports self-referencing hierarchy.
getHierarchyFieldId()
public function getHierarchyFieldId(): ?string
Returns the hierarchy field name (e.g., parent_id).
hierarchyParent()
public function hierarchyParent(): ?BelongsTo
Defines BelongsTo relation to parent in hierarchy.
Example:
$category = Category::find(1);
$parent = $category->hierarchyParent; // Parent category
hierarchyChildren()
public function hierarchyChildren(): HasMany
Defines HasMany relation to children in hierarchy.
Example:
$category = Category::find(1);
$children = $category->hierarchyChildren; // Child categories
isHierarchyRoot()
public function isHierarchyRoot(): bool
Checks if record is root node (has no parent).
getHierarchyAncestors()
public function getHierarchyAncestors(): \Illuminate\Support\Collection
Returns all ancestors from parent to root.
Example:
$category = Category::find(5);
$ancestors = $category->getHierarchyAncestors();
// Collection of parent, grandparent, great-grandparent, etc.
getHierarchyDescendants()
public function getHierarchyDescendants(?int $maxDepth = null, int $currentDepth = 0): \Illuminate\Support\Collection
Returns all descendants recursively.
Maximum depth to traverse (null = unlimited)
Current depth in recursion (internal use)
Example:
$category = Category::find(1);
$descendants = $category->getHierarchyDescendants(2); // 2 levels deep
Validation Methods
rules()
protected function rules(string $scenario): array
Define validation rules per scenario. Override in your model.
Example:
protected function rules(string $scenario): array
{
if ($scenario === 'create') {
return [
'email' => 'required|email|unique:users',
'name' => 'required|min:3',
];
}
return [
'email' => 'email',
'name' => 'min:3',
];
}
self_validate()
public function self_validate(string $scenario = 'create', bool $specific = false, bool $validate_pk = true): array
Validates current model attributes.
Validation scenario (create or update)
If true, only validate fields present in attributes
Include primary key in validation
[
'success' => bool,
'errors' => array,
'model' => string // Model class name
]
validate_all()
public function validate_all(array $attributes, string $scenario = 'create', bool $specific = false): array
Validates model and all parent models in hierarchy.
['success' => true] // or ['success' => false, 'errors' => [...]]
save_model()
public function save_model(array $attributes = [], string $scenario = 'create'): array
Validates and saves the model (and parent hierarchy if applicable).
Attributes to save (uses current attributes if empty)
[
'success' => true,
'model' => array // Saved attributes
]
// or on error:
[
'success' => false,
'errors' => array
]
Static Methods
create_model()
static public function create_model(array $params): array
Creates one or more model instances.
Example:
// Single record
$result = User::create_model(['name' => 'John', 'email' => '[email protected]']);
// Multiple records
$result = User::create_model(['user' => [
['name' => 'John', 'email' => '[email protected]'],
['name' => 'Jane', 'email' => '[email protected]']
]]);
update_multiple()
static public function update_multiple(array $params): array
Updates multiple records at once.
Example:
$result = User::update_multiple([
['id' => 1, 'status' => 'active'],
['id' => 2, 'status' => 'inactive']
]);
destroy_model()
static public function destroy_model(mixed $id): array
Deletes a model by ID.
['success' => true, 'model' => Model]
MongoDB Relation Methods
These methods enable relationships between SQL and MongoDB databases.
belongsToMongo()
public function belongsToMongo(
string $related,
?string $foreignKey = null,
?string $ownerKey = null,
?string $relation = null
): MongoBelongTo
Defines a BelongsTo relationship with a MongoDB model.
Example:
public function author()
{
return $this->belongsToMongo(MongoUser::class, 'author_id');
}
hasManyMongo()
public function hasManyMongo(
string $related,
?string $foreignKey = null,
?string $localKey = null
): MongoHasMany|HasMany
Defines a HasMany relationship with a MongoDB model.
Example:
public function logs()
{
return $this->hasManyMongo(MongoLog::class, 'user_id');
}
hasOneMongo()
public function hasOneMongo(
string $related,
?string $foreignKey = null,
?string $localKey = null
): HasOneOrMany
Defines a HasOne relationship with a MongoDB model.
Usage Example
use Ronu\RestGenericClass\Core\Models\BaseModel;
class Category extends BaseModel
{
const MODEL = 'category';
const RELATIONS = ['parent', 'children', 'products'];
const HIERARCHY_FIELD_ID = 'parent_id';
protected $fillable = ['name', 'slug', 'parent_id', 'is_active'];
protected array $fieldsByRole = [
'admin' => ['is_active', 'featured']
];
protected function rules(string $scenario): array
{
if ($scenario === 'create') {
return [
'name' => 'required|min:3|unique:categories',
'slug' => 'required|unique:categories',
];
}
return [
'name' => 'min:3',
];
}
public function products()
{
return $this->hasMany(Product::class);
}
}
// Usage
$category = Category::find(1);
$children = $category->hierarchyChildren;
$ancestors = $category->getHierarchyAncestors();
$descendants = $category->getHierarchyDescendants(2);
// Validation
$result = $category->validate_all([
'name' => 'Electronics',
'slug' => 'electronics'
], 'create');
if ($result['success']) {
// Save the category
}
BaseService
Service layer with query building and CRUD operations
RestController
Controller exposing RESTful API endpoints