Benefits of Apex Trigger Framework:
- A single trigger per object gives complete control over the order of execution.
- Implementing trigger logic in handler class, makes unit testing and maintenance much easier.
- Implementation of best practices.
- It enforces trigger to work in a consistent way.
- It allows to prevent trigger recursion without adding separate logic.
- It is easier to work on a single trigger for multiple developers and reduce the development lifecycle.
- It allows to make decisions to active/inactive the trigger from transaction and UI as well.
Each trigger must be implemented in a custom setting that allows the trigger to be active/inactive from UI.
Custom Settings: (Trigger Setting)
Trigger Setting Data: (Create record for each trigger)
Trigger Interface: (ITriggerHandler)
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Trigger Handler Interface
*/
public interface ITriggerHandler{
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework before insert of the records
@Parameters : List<sObject> newList , Map<Id, sObject> newMap
*/
void beforeInsert(List<sObject> newList);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework after insert of the records
@Parameters : List<sObject> newList
*/
void afterInsert(List<sObject> newList, Map<Id, sObject> newMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework before update of the records
@Parameters : List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap
*/
void beforeUpdate(List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework after update of the records
@Parameters : List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap
*/
void afterUpdate(List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework before delete of the records
@Parameters : List<sObject> oldList , Map<Id, sObject> oldMap
*/
void beforeDelete(List<sObject> oldList , Map<Id, sObject> oldMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework after delete of the records
@Parameters : Map<Id, sObject> oldMap
*/
void afterDelete(List<sObject> oldList , Map<Id, sObject> oldMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework after undelete of the records
@Parameters : List<sObject> newList, Map<Id, sObject> newMap
*/
void afterUnDelete(List<sObject> newList, Map<Id, sObject> newMap);
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Called by the trigger framework to check the trigger for the object is enabled or disabled
@Parameters :
*/
Boolean isDisabled();
}
Trigger Dispatcher Class:(TriggerDispatcher)
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Trigger Dispatcher.
*/
public class TriggerDispatcher {
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : It will invoke the appropriate methods on the handler depending on the trigger context.
@Parameters : ITriggerHandler handler
*/
public static void run(ITriggerHandler handler, string triggerName){
//Check if the trigger is disabled
if (handler.IsDisabled()){
return;
}
//Get the trigger active information from custom settings by trigger name
Boolean isActive = TriggerSetting__c.getValues(triggerName).isActive__c;
if(isActive){
//Check trigger context from trigger operation type
switch on Trigger.operationType {
when BEFORE_INSERT {
//Invoke before insert trigger handler
handler.beforeInsert(trigger.new);
}
when AFTER_INSERT {
//Invoke after insert trigger handler
handler.afterInsert(trigger.new, trigger.newMap);
}
when BEFORE_UPDATE {
//Invoke before update trigger handler
handler.beforeUpdate(trigger.new, trigger.newMap, trigger.old, trigger.oldMap);
}
when AFTER_UPDATE {
//Invoke after update trigger handler
handler.afterUpdate(trigger.new, trigger.newMap, trigger.old, trigger.oldMap);
}
when BEFORE_DELETE {
//Invoke before delete trigger handler
handler.beforeDelete(trigger.old, trigger.oldMap);
}
when AFTER_DELETE {
//Invoke after delete trigger handler
handler.afterDelete(trigger.old, trigger.oldMap);
}
when AFTER_UNDELETE {
//Invoke after undelete trigger handler
handler.afterUnDelete(trigger.new, trigger.newMap);
}
}
}
}
}
Account Object Trigger: (AccountTrigger)
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Account Object Trigger.
*/
trigger AccountTrigger on Account(before insert, after insert, before update, after update, before delete, after delete, after unDelete) {
TriggerDispatcher.run(new AccountTriggerHandler(), 'AccountTrigger');
}
Account Object Trigger Handler: (AccountTriggerHandler)
/*
@Author : Biswajeet Samal
@CreatedDate : 20th Oct 2019
@Description : Account Object Trigger Handler.
*/
public class AccountTriggerHandler implements ITriggerHandler{
//Use this variable to disable this trigger from transaction
public static Boolean TriggerDisabled = false;
//check if the trigger is disabled from transaction
public Boolean isDisabled(){
return TriggerDisabled;
}
public void beforeInsert(List<sObject> newList) {
}
public void afterInsert(List<sObject> newList , Map<Id, sObject> newMap) {
}
public void beforeUpdate(List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap) {
}
public void afterUpdate(List<sObject> newList, Map<Id, sObject> newMap, List<sObject> oldList, Map<Id, sObject> oldMap) {
}
public void beforeDelete(List<sObject> oldList , Map<Id, sObject> oldMap) {
}
public void afterDelete(List<sObject> oldList , Map<Id, sObject> oldMap) {
}
public void afterUnDelete(List<sObject> newList, Map<Id, sObject> newMap) {
}
}