Class Name: TriggerHandler¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/TriggerHandler.cls
API Name: TriggerHandler Type: Utility (Framework/Base Class) Test Coverage: [To be verified via TriggerHandlerTest]
Business Purpose¶
The TriggerHandler class provides a standardized framework for implementing trigger logic across all Salesforce objects. This ensures consistent trigger structure, separation of concerns between triggers and business logic, testability through virtual methods, and support for all trigger contexts. This foundational framework class is used throughout the org's trigger architecture to maintain code quality and maintainability.
Class Overview¶
Scope and Sharing¶
- Sharing Model: Not specified (inherits from context)
- Access Modifier: public virtual
- Interfaces Implemented: None
Key Responsibilities¶
- Route trigger execution to appropriate handler methods based on trigger context
- Provide virtual methods for all seven trigger contexts (before/after insert/update/delete/undelete)
- Validate trigger execution context to prevent misuse outside of triggers
- Support testing via @TestVisible triggerContext override
- Provide extensibility point via andFinally() hook method
Public Methods¶
Constructor¶
Purpose: Validates that handler is being used in appropriate context (within trigger or test).
Parameters: None
Returns: N/A (Constructor)
Throws:
- TriggerHandlerException: When handler is instantiated outside of trigger context or test execution
Business Logic: Validates that either Trigger.isExecuting is true OR Test.isRunningTest() is true. If neither condition is met, throws an exception to prevent accidental misuse of the handler outside triggers.
Architecture Pattern Example:
Trigger File (e.g., AccountTrigger.trigger):
trigger AccountTrigger on Account (before insert, before update, after insert, after update) {
new AccountTriggerHandler().execute();
}
execute¶
Purpose: Routes trigger execution to the appropriate virtual method based on the current trigger operation context.
Parameters: None
Returns: void
Business Logic: Uses a switch statement to determine the current trigger operation context (with support for test override via triggerContext variable). Routes to the appropriate protected virtual method and then calls andFinally() hook for post-processing. Supports all seven trigger contexts: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, and AFTER_UNDELETE.
Usage Example:
// In trigger file
trigger AccountTrigger on Account (before insert, before update, after insert, after update) {
new AccountTriggerHandler().execute();
}
// In handler class
public class AccountTriggerHandler extends TriggerHandler {
protected override void beforeInsert(List<SObject> newRecords) {
// Custom logic for before insert
}
}
Private/Helper Methods¶
Virtual Handler Methods¶
All handler methods below are protected virtual and meant to be overridden by subclasses:
beforeInsert¶
Purpose: Handle before insert logic for new records (records do not yet have IDs) Called By: execute() method when Trigger.operationType is BEFORE_INSERT
beforeUpdate¶
Purpose: Handle before update logic with access to both new and old values Called By: execute() method when Trigger.operationType is BEFORE_UPDATE
beforeDelete¶
Purpose: Handle before delete logic (can prevent deletion or perform logging) Called By: execute() method when Trigger.operationType is BEFORE_DELETE
afterInsert¶
Purpose: Handle after insert logic (records now have IDs, can create related records) Called By: execute() method when Trigger.operationType is AFTER_INSERT
afterUpdate¶
Purpose: Handle after update logic with access to both new and old values Called By: execute() method when Trigger.operationType is AFTER_UPDATE
afterDelete¶
Purpose: Handle after delete logic (cleanup, archiving, etc.) Called By: execute() method when Trigger.operationType is AFTER_DELETE
afterUndelete¶
Purpose: Handle after undelete logic (restore relationships, etc.) Called By: execute() method when Trigger.operationType is AFTER_UNDELETE
andFinally¶
Purpose: Runs after every trigger context to provide post-processing hook Called By: execute() method after routing to specific handler Use Cases: Apex Rollup pattern, logging, auditing, cleanup operations
TriggerHandlerException (Inner Class)¶
Purpose: Custom exception for framework errors Called By: Constructor when validation fails
Dependencies¶
Apex Classes¶
- None (base class - does not depend on other custom classes)
Salesforce Objects¶
- All SObjects (generic framework supports any object type)
Custom Settings/Metadata¶
- None
External Services¶
- None
Design Patterns¶
- Template Method Pattern: Base class defines algorithm structure (execute()), subclasses implement specific steps
- Virtual Methods: All handler methods are virtual to allow selective overriding by subclasses
- Single Trigger Pattern: One trigger file per object, all logic delegated to handler
- Separation of Concerns: Trigger files only instantiate and execute handlers
- Hook Method Pattern: andFinally() provides extensibility point for post-processing
Governor Limits Considerations¶
SOQL Queries: N/A - Framework class does not execute queries DML Operations: N/A - Framework class does not perform DML CPU Time: Minimal - Simple routing logic only Heap Size: Minimal - No data collection or caching
Bulkification: Framework supports bulk patterns through List and Map parameters Async Processing: Not applicable - synchronous routing only
Error Handling¶
Strategy: Constructor validation with custom exception Logging: No built-in logging (left to subclass implementations) User Notifications: Exceptions propagate to trigger context for standard error handling
Security Considerations¶
Sharing Rules: Not specified - inherits from subclass implementation Field-Level Security: Not applicable - framework does not access fields CRUD Permissions: Not applicable - framework does not perform DML Input Validation: Validates execution context in constructor
Test Class¶
Test Class: TriggerHandlerTest.cls Coverage: [To be verified] Test Scenarios Covered: - Valid trigger context execution for all seven contexts - Invalid context validation (outside trigger) - Virtual method overriding - andFinally() hook execution - Test context override functionality
Changes & History¶
- 2024-12-20: Initial implementation by Ryan O'Sullivan - Trigger framework foundation
⚠️ Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- None identified
HIGH - Address Soon After Go-Live¶
- None identified
MEDIUM - Future Enhancement¶
- No Recursion Control: Framework doesn't prevent infinite loops when triggers call DML that fires same trigger
- Test.isRunningTest() Anti-pattern: Constructor uses Test.isRunningTest() which can cause code to behave differently in tests vs production
- @TestVisible on TriggerHandlerException: Unnecessary annotation (exceptions are accessible in tests by default)
LOW - Monitor¶
- No Context Tracking: Doesn't track which handlers have executed in current transaction
- triggerContext Test Override: While useful for testing, breaks encapsulation slightly
Maintenance Notes¶
Complexity: Low Recommended Review Schedule: Annually (stable framework class) Key Maintainer Notes: - This is a foundational framework class used by all trigger handlers - changes should be rare and carefully reviewed - Subclasses must not modify core routing logic - only override virtual methods - When adding new trigger handlers, ensure they extend this base class for consistency - Test context override (triggerContext variable) is for testing only - never use in production code - The andFinally() hook executes after every trigger context - be mindful of cumulative processing costs