BranchesTable
extends BaseTable
in package
Branches Model - Hierarchical Organizational Structure Management for KMP
Manages the organizational hierarchy for the Kingdom Management Portal, supporting nested tree structures for kingdoms, principalities, baronies, shires, and other administrative divisions. Provides efficient tree operations with aggressive caching and automatic integrity maintenance.
Core Architecture:
- Extends BaseTable for KMP cache management and branch scoping
- Implements Tree behavior for nested set model operations
- Provides specialized cache invalidation for hierarchical data
- Supports JSON field storage for flexible branch configuration
- Integrates with authorization system for organizational access control
Tree Structure Management:
- Nested set model (lft/rght) for efficient tree queries
- Automatic tree recovery and integrity maintenance
- Cached descendant and ancestor lookups for performance
- Support for unlimited hierarchy depth
- Circular reference detection and prevention
Performance Optimization:
- Two-tier caching strategy: descendants and parents lookups
- Cache invalidation on tree structure changes
- Efficient threaded tree queries for UI display
- Batch operations for tree restructuring
Member Association:
- Links members to organizational units
- Supports member visibility and access control
- Enables branch-specific role assignments
- Provides organizational reporting capabilities
Validation & Business Rules:
- Unique branch names across entire organization
- Required name and location fields
- Circular reference prevention in parent-child relationships
- JSON schema validation for links field
Authorization Integration:
- Branch-scoped data access control
- Hierarchical permission inheritance
- Integration with policy-based authorization
- Support for organizational role-based access
Usage Examples:
// Tree operations
$branchesTable = $this->getTableLocator()->get('Branches');
// Get all descendants of a branch
$descendantIds = $branchesTable->getAllDecendentIds($branchId);
// Get path to root for breadcrumbs
$parentIds = $branchesTable->getAllParents($branchId);
// Get threaded tree for navigation
$tree = $branchesTable->getThreadedTree();
// Find children for dropdown
$children = $branchesTable->find('children', ['for' => $parentId, 'direct' => true]);
// Tree list for form selects
$treeList = $branchesTable->find('treeList', ['spacer' => '--']);
Tree Recovery & Maintenance:
// Automatic recovery on application startup
$branchesTable->recover(); // Rebuilds lft/rght values
// Handle tree structure changes
$branch->parent_id = $newParentId;
$branchesTable->save($branch); // Triggers tree rebalancing
Caching Strategy:
- Static cache keys: none (all data is dynamic)
- ID-based caches: descendants_[id], parents_[id] in 'branch_structure' config
- Group caches: 'security' group for authorization data
- Cache TTL: Managed by CakePHP cache configuration
- Invalidation: On any save operation affecting tree structure
Database Schema:
- Standard tree behavior fields (lft, rght, parent_id)
- JSON links field for external resource storage
- Audit trail fields (created, modified, created_by, modified_by)
- Soft deletion support (deleted, deleted_date)
- Branch type classification and domain association
Tags
Table of Contents
Constants
- CACHE_GROUPS_TO_CLEAR = ['security']
- CACHES_TO_CLEAR = []
- Cache configuration for branch hierarchy data
- ID_CACHES_TO_CLEAR = [['descendants_', 'branch_structure'], ['parents_', 'branch_structure']]
Properties
Methods
- addBranchScopeQuery() : SelectQuery
- Add branch-based data scoping to a query.
- afterDelete() : void
- After delete hook to capture impersonation audit trail entries.
- afterSave() : void
- After-save handler for automatic cache invalidation.
- buildRules() : RulesChecker
- Returns a rules checker object for application integrity validation
- findOrCreate() : Branch
- get() : Branch
- getAllDecendentIds() : array<string|int, int>
- Get all descendant branch IDs with aggressive caching
- getAllParents() : array<string|int, int>
- Get all parent branch IDs with aggressive caching
- getSchema() : TableSchemaInterface
- Get database schema with JSON field configuration
- getThreadedTree() : array<string|int, Branch>
- Get threaded tree structure for UI display
- initialize() : void
- Initialize method - Configure table relationships and behaviors
- newEntities() : array<string|int, Branch>
- newEntity() : Branch
- patchEntities() : array<string|int, Branch>
- patchEntity() : Branch
- save() : Branch|bool
- validationDefault() : Validator
- Default validation rules for branch data integrity
- getDescendantsLookup() : array<int, array<string|int, int>>
- Build descendants lookup table for all branches
- getParentsLookup() : array<int, array<string|int, int>>
- Build parents lookup table for all branches
- logImpersonationAction() : void
- Record impersonated writes to audit log table.
Constants
CACHE_GROUPS_TO_CLEAR
protected
array<string|int, string>
CACHE_GROUPS_TO_CLEAR
= ['security']
Cache groups to clear entirely on save
CACHES_TO_CLEAR
Cache configuration for branch hierarchy data
protected
array<string|int, array{string, string}>
CACHES_TO_CLEAR
= []
Defines the caching strategy for branch tree operations to optimize performance of hierarchical queries. Uses specialized cache groups for different types of branch data.
Cache Strategy:
- No static caches (all branch data is dynamic)
- ID-based caches for descendants and parents lookups
- Security group cache for authorization data
- Cache invalidation on any tree structure changes
Performance Impact:
- Descendants cache: O(1) lookup vs O(n) tree traversal
- Parents cache: O(1) lookup vs O(log n) tree walk
- Security cache: Pre-computed authorization scopes
Static cache entries to clear on save
Tags
ID_CACHES_TO_CLEAR
protected
array<string|int, array{string, string}>
ID_CACHES_TO_CLEAR
= [['descendants_', 'branch_structure'], ['parents_', 'branch_structure']]
Entity-ID cache prefixes to clear on save
Properties
$entities
public
array<string|int, Branch>
$entities
Methods
addBranchScopeQuery()
Add branch-based data scoping to a query.
public
addBranchScopeQuery(SelectQuery $query, array<string|int, int> $branchIDs) : SelectQuery
Child tables should override for custom branch relationships.
Parameters
- $query : SelectQuery
-
The query to modify
- $branchIDs : array<string|int, int>
-
Authorized branch IDs
Return values
SelectQuery —Query with branch filtering
afterDelete()
After delete hook to capture impersonation audit trail entries.
public
afterDelete(EventInterface $event, EntityInterface $entity, ArrayObject $options) : void
Parameters
- $event : EventInterface
-
Delete event
- $entity : EntityInterface
-
Entity being deleted
- $options : ArrayObject
-
Delete options
afterSave()
After-save handler for automatic cache invalidation.
public
afterSave(EventInterface $event, EntityInterface $entity, ArrayObject $options) : void
Parameters
- $event : EventInterface
-
The afterSave event
- $entity : EntityInterface
-
The saved entity
- $options : ArrayObject
-
Save options
buildRules()
Returns a rules checker object for application integrity validation
public
buildRules(RulesChecker $rules) : RulesChecker
Implements business rules that ensure organizational data integrity beyond basic field validation. Enforces unique constraints and referential integrity for the branch hierarchy.
Business Rules:
- Unique branch names across entire organization
- Referential integrity for parent-child relationships
- Tree structure consistency (handled by Tree behavior)
Rule Processing:
- isUnique: Prevents duplicate branch names
- Additional rules can be added for complex business logic
- Integrates with Tree behavior for hierarchy validation
Parameters
- $rules : RulesChecker
-
The rules object to be modified.
Return values
RulesChecker —Configured rules checker with branch-specific rules
findOrCreate()
public
findOrCreate(mixed $search[, callable|null $callback = = 'null' ][, array<string|int, mixed> $options = = '[]' ]) : Branch
Parameters
- $search : mixed
- $callback : callable|null = = 'null'
- $options : array<string|int, mixed> = = '[]'
Return values
Branchget()
public
get(mixed $primaryKey[, array<string|int, mixed> $options = = '[]' ]) : Branch
Parameters
- $primaryKey : mixed
- $options : array<string|int, mixed> = = '[]'
Return values
BranchgetAllDecendentIds()
Get all descendant branch IDs with aggressive caching
public
getAllDecendentIds(int $id) : array<string|int, int>
Retrieves all descendant branch IDs for a given branch, using a two-tier caching strategy for optimal performance. This method is critical for authorization and organizational reporting.
Caching Strategy:
- Check individual cache for specific branch ID
- If miss, rebuild entire descendants lookup table
- Cache all branch descendants for future requests
- Return specific branch descendants
Performance Characteristics:
- Cache hit: O(1) lookup time
- Cache miss: O(n) rebuild time, but caches all branches
- Memory efficient: Only stores branch IDs, not full entities
- TTL: Managed by 'branch_structure' cache configuration
Use Cases:
- Authorization: Check permissions for branch hierarchy
- Reporting: Generate reports for organizational units
- Member management: Find members in branch and sub-branches
- Event planning: Determine branch participation scope
Usage Examples:
// Get all branches under Kingdom of Atlantia
$atlantiaDescendants = $branchesTable->getAllDecendentIds($atlantiaId);
// Returns: [principality1, principality2, barony1, barony2, shire1, ...]
// Authorization check for hierarchical permissions
$userBranches = $user->getPermission('manage_events')->branch_ids;
$canManage = in_array($eventBranchId, $userBranches);
// Member search within organizational scope
$members = $membersTable->find()
->where(['branch_id IN' => $branchesTable->getAllDecendentIds($branchId)]);
Parameters
- $id : int
-
The branch ID to get descendants for
Return values
array<string|int, int> —Array of descendant branch IDs (empty array if no descendants)
getAllParents()
Get all parent branch IDs with aggressive caching
public
getAllParents(int $id) : array<string|int, int>
Retrieves all parent branch IDs for a given branch, providing the complete path from the branch to the root of the hierarchy. Uses caching strategy similar to descendants for optimal performance.
Caching Strategy:
- Check individual cache for specific branch ID
- If miss, rebuild entire parents lookup table
- Cache all branch parents for future requests
- Return specific branch parents
Return Format:
- Array of parent IDs from immediate parent to root
- Empty array if branch is at root level
- Maintains hierarchical order (parent, grandparent, great-grandparent, ...)
Use Cases:
- Breadcrumb generation for navigation
- Permission inheritance checking
- Organizational reporting and analytics
- Branch hierarchy validation
Usage Examples:
// Get path to root for breadcrumbs
$parentIds = $branchesTable->getAllParents($baronyId);
// Returns: [principalityId, kingdomId] (immediate parent to root)
// Build breadcrumb navigation
$breadcrumbs = [];
foreach ($parentIds as $parentId) {
$breadcrumbs[] = $branchesTable->get($parentId);
}
// Check permission inheritance
$hasInheritedPermission = false;
foreach ($branchesTable->getAllParents($branchId) as $parentId) {
if ($user->hasPermissionForBranch($permission, $parentId)) {
$hasInheritedPermission = true;
break;
}
}
Parameters
- $id : int
-
The branch ID to get parents for
Return values
array<string|int, int> —Array of parent branch IDs in hierarchical order
getSchema()
Get database schema with JSON field configuration
public
getSchema() : TableSchemaInterface
Customizes the database schema to properly handle the JSON links field. This ensures that the links field is correctly typed for JSON operations and database storage.
JSON Field Configuration:
- links: Stores external resource URLs and configuration
- Supports nested JSON structures for complex link configurations
- Enables database-level JSON queries and operations
Usage Examples:
// JSON links structure
$branch->links = [
'website' => 'https://atlantia.sca.org',
'calendar' => 'https://calendar.atlantia.sca.org',
'newsletter' => 'https://acorn.atlantia.sca.org',
'social' => [
'facebook' => 'https://facebook.com/atlantia.sca',
'discord' => 'https://discord.gg/atlantia'
]
];
Return values
TableSchemaInterface —Configured schema with JSON field typing
getThreadedTree()
Get threaded tree structure for UI display
public
getThreadedTree() : array<string|int, Branch>
Retrieves the entire branch hierarchy as a threaded tree structure, optimized for UI display such as navigation menus, dropdowns, and organizational charts. Uses Tree behavior's efficient threaded find.
Tree Structure:
- Nested array with 'children' key for sub-branches
- Includes minimal fields for performance (id, name, parent_id)
- Maintains hierarchical relationships and ordering
- Ready for direct use in view templates
Performance Considerations:
- Efficient single query using Tree behavior
- Minimal field selection for reduced memory usage
- No caching (structure changes frequently)
- Use sparingly for large hierarchies
Usage Examples:
// Generate navigation menu
$tree = $branchesTable->getThreadedTree();
foreach ($tree as $kingdom) {
echo $kingdom->name;
foreach ($kingdom->children as $principality) {
echo " " . $principality->name;
foreach ($principality->children as $barony) {
echo " " . $barony->name;
}
}
}
// Generate organizational chart data
$chartData = $this->convertTreeToChartFormat($tree);
Return values
array<string|int, Branch> —Threaded tree structure with nested children
initialize()
Initialize method - Configure table relationships and behaviors
public
initialize(array<string|int, mixed> $config) : void
Sets up the BranchesTable with all necessary associations, behaviors, and configuration for hierarchical branch management. Establishes parent-child relationships, member associations, and enables tree operations with audit trails.
Tree Behavior Configuration:
- Nested set model for efficient tree queries
- Automatic lft/rght field management
- Support for tree recovery and integrity maintenance
- Parent-child relationship handling
Behavioral Features:
- Timestamp: Automatic created/modified tracking
- Footprint: User attribution for data changes
- Trash: Soft deletion with recovery capabilities
- Tree: Hierarchical data management
Association Setup:
- Self-referential parent-child relationships
- One-to-many member associations
- Support for unlimited hierarchy depth
Parameters
- $config : array<string|int, mixed>
-
The configuration for the Table.
newEntities()
public
newEntities(array<string|int, mixed> $data[, array<string|int, mixed> $options = = '[]' ]) : array<string|int, Branch>
Parameters
- $data : array<string|int, mixed>
- $options : array<string|int, mixed> = = '[]'
Return values
array<string|int, Branch>newEntity()
public
newEntity([array<string|int, mixed> $data = = '[]' ][, array<string|int, mixed> $options = = '[]' ]) : Branch
Parameters
- $data : array<string|int, mixed> = = '[]'
- $options : array<string|int, mixed> = = '[]'
Return values
BranchpatchEntities()
public
patchEntities(iterable<string|int, mixed> $entities, array<string|int, mixed> $data[, array<string|int, mixed> $options = = '[]' ]) : array<string|int, Branch>
Parameters
- $entities : iterable<string|int, mixed>
- $data : array<string|int, mixed>
- $options : array<string|int, mixed> = = '[]'
Return values
array<string|int, Branch>patchEntity()
public
patchEntity(EntityInterface $entity, array<string|int, mixed> $data[, array<string|int, mixed> $options = = '[]' ]) : Branch
Parameters
- $entity : EntityInterface
- $data : array<string|int, mixed>
- $options : array<string|int, mixed> = = '[]'
Return values
Branchsave()
public
save(EntityInterface $entity[, array<string|int, mixed> $options = = '[]' ]) : Branch|bool
Parameters
- $entity : EntityInterface
- $options : array<string|int, mixed> = = '[]'
Return values
Branch|boolvalidationDefault()
Default validation rules for branch data integrity
public
validationDefault(Validator $validator) : Validator
Implements comprehensive validation for branch entities to ensure data quality and organizational consistency. Enforces unique naming across the entire hierarchy and validates required organizational information.
Validation Rules:
- Name: Required, non-empty, unique across all branches
- Location: Required, non-empty string for geographic identification
- Additional validations applied through business rules
Security Considerations:
- Unique name constraint prevents organizational confusion
- Required fields ensure complete branch registration
- Validates against SQL injection and XSS attacks
Usage Examples:
// Valid branch data
$validData = [
'name' => 'Barony of Windmasters Hill',
'location' => 'Northern Virginia, USA',
'type' => 'Barony',
'parent_id' => $atlantiaId
];
// Validation errors
$invalidData = [
'name' => '', // Error: required field
'location' => '' // Error: required field
];
$duplicateData = [
'name' => 'Kingdom of Atlantia' // Error: name already exists
];
Parameters
- $validator : Validator
-
Validator instance.
Return values
Validator —Configured validator with branch-specific rules
getDescendantsLookup()
Build descendants lookup table for all branches
protected
getDescendantsLookup() : array<int, array<string|int, int>>
Generates a complete lookup table mapping each branch ID to its array of descendant branch IDs. This method is called when cache misses occur and rebuilds the entire descendant relationship cache.
Algorithm:
- Get threaded tree structure
- Recursively process each node bottom-up
- Collect child IDs and merge with grandchild IDs
- Build complete descendant arrays for each branch
Performance:
- O(n) time complexity for complete rebuild
- Efficient recursive tree processing
- Bottom-up approach ensures complete descendant collection
- Memory efficient storage of descendant relationships
Usage by Authorization System:
- Permission inheritance down the hierarchy
- Branch-scoped data access control
- Organizational reporting and analytics
- Member visibility and management
Return values
array<int, array<string|int, int>> —Lookup table mapping branch IDs to descendant ID arrays
getParentsLookup()
Build parents lookup table for all branches
protected
getParentsLookup() : array<int, array<string|int, int>>
Generates a complete lookup table mapping each branch ID to its array of parent branch IDs. This method is called when cache misses occur and rebuilds the entire parent relationship cache.
Algorithm:
- Get threaded tree structure
- Recursively traverse each node
- Build parent ID arrays for each branch
- Store complete lookup table for caching
Performance:
- O(n) time complexity for complete rebuild
- Efficient single-pass tree traversal
- Memory efficient storage of parent relationships
- Infrequent execution due to caching
Return values
array<int, array<string|int, int>> —Lookup table mapping branch IDs to parent ID arrays
logImpersonationAction()
Record impersonated writes to audit log table.
protected
logImpersonationAction(string $defaultOperation, EntityInterface $entity) : void
Parameters
- $defaultOperation : string
-
Operation fallback (save/delete)
- $entity : EntityInterface
-
Affected entity