Salesforce Apex Trigger Framework
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) { } }