triggerFrameWork

Trigger Framework in Salesforce Apex

APEX

Benefits of Apex Trigger Framework:

  1. It allows to make decisions to active/inactive the trigger from transaction and UI as well.
  2. It allows to prevent trigger recursion without adding separate logic.
  3. Implementing trigger logic in handler class, makes unit testing and maintenance much easier.

So Each trigger must be implemented in a custom setting or Custom MetaData that allows the trigger to be active/inactive from UI. Means we can make activate or Deactivate trigger on production directly with help of Custom Setting or Custom Meta Data.

  1. Trigger Handler Pattern

Trigger :

trigger objectTrigger on Object (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
     
    objectTriggerHandler handler = new objectTriggerHandler();
     
    //Before Insert
    if(Trigger.isInsert && Trigger.isBefore){
        handler.OnBeforeInsert(Trigger.new);
    }
    //After Insert
    else if(Trigger.isInsert && Trigger.isAfter){
        handler.OnAfterInsert(Trigger.new);
    }
    //Before Update
    else if(Trigger.isUpdate && Trigger.isBefore){
        handler.OnBeforeUpdate(Trigger.old, Trigger.new, Trigger.newMap);
    }
    //After Update
    else if(Trigger.isUpdate && Trigger.isAfter){
        handler.OnAfterUpdate(Trigger.old, Trigger.new, Trigger.newMap);
    }
    //Before Delete
    else if(Trigger.isDelete && Trigger.isBefore){
        handler.OnBeforeDelete(Trigger.old, Trigger.oldMap);
    }
    //After Delete
    else if(Trigger.isDelete && Trigger.isAfter){
        handler.OnAfterDelete(Trigger.old, Trigger.oldMap);
    }
    //After Undelete
    else if(Trigger.isUnDelete){
        handler.OnUndelete(Trigger.new);
    }
}

Trigger Handler Class:

public with sharing class ObjectTriggerHandler {
     
    private boolean isExecuting = false;
     
    public ObjectTriggerHandler(boolean isExecuting){
        this.isExecuting = isExecuting;
    }
     
    public void OnBeforeInsert(List<Object> newObjects){
        //EXECUTE BEFORE INSERT LOGIC
    }
     
    public void OnAfterInsert(List<Object> newObjects){
        //EXECUTE AFTER INSERT LOGIC
    }
     
    public void OnBeforeUpdate(List<Object> oldObjects, List<Object> updatedObjects, Map<Id, Object> ObjectMap){
        //BEFORE UPDATE LOGIC
    }
     
    public void OnAfterUpdate(List<Object> oldObjects, List<Object> updatedObjects, Map<Id, Object> ObjectMap){
        //AFTER UPDATE LOGIC
    }
     
    public void OnBeforeDelete(List<Object> ObjectsToDelete, Map<Id, Object> ObjectMap){
        //BEFORE DELETE LOGIC
    }
     
    public void OnAfterDelete(List<Object> deletedObjects, Map<Id, Object> ObjectMap){
        //AFTER DELETE LOGIC
    }
     
    public void OnUndelete(List<Object> restoredObjects){
        //AFTER UNDELETE LOGIC
    }
     
    public boolean IsTriggerContext{
        get{ return isExecuting;}
    }
}
  • Apex Class that handles trigger logic
  • Allows code to be called from other code or tests
  • It uses specific Trigger contexts and Trigger variables for routing purpose.
  • Keep Triggers Simple and easy to understand
  • Allow for greater flexibility
  • Make code reusable
  • Unit tests are much easier

LIMITATION OF TRIGGER HANDLER PATTERN:

  • Still Repeated code
  • Less code reusability
  • Partial one trigger per object

2. Trigger Framework using a Virtual Class:-

The framework uses the TriggerHandlerBase virtual class to handle dispatching to the correct “event” method such as “onBeforeInsert” and “onBeforeUpdate” in the derived handler class. One implements the derived handler class and overrides the desired event methods to keep the code simple and clean. To use the trigger handler, one instantiates it in the Trigger and invokes its run method. The trigger should define all the events so that if one needs to use that event in the future, one only has to override the event method in the handler class.

TriggerHandlerBase:-

public virtual with sharing class TriggerHandlerBase {

    public void run() {
        // dispatch to the correct handler method
        if(Trigger.isBefore) {
            if (Trigger.isInsert) {
                this.beforeInsert(Trigger.New);
            }
            else if(Trigger.isUpdate) {
                this.beforeUpdate(Trigger.oldMap, Trigger.newMap);
            }
            else if(Trigger.isDelete) {
                this.beforeDelete(Trigger.oldMap);
            }
        }
        // Is After
        else {
            if(Trigger.isInsert) {
                this.afterInsert(Trigger.New);
            }
            else if(Trigger.isUpdate) {
                this.afterUpdate(Trigger.oldMap, Trigger.newMap);
            }
            else if(Trigger.isDelete) {
                this.afterDelete(Trigger.oldMap);
            }
            else if(Trigger.isUndelete) {
                this.afterUndelete(Trigger.New);
            }
        }
    }

    protected virtual void beforeInsert(List<Sobject> newRecords) { }

    protected virtual void beforeUpdate(Map<Id, Sobject> oldRecordsMap, Map<Id, Sobject> newRecordsMap) { }

    protected virtual void beforeDelete(Map<Id, Sobject> deletedRecordsMap) { }

    protected virtual void afterInsert(List<Sobject> newRecords) { }

    protected virtual void afterUpdate(Map<Id, Sobject> oldRecordsMap, Map<Id, Sobject> newRecordsMap) { }

    protected virtual void afterDelete(Map<Id, Sobject> deletedRecordsMap) { }

    protected virtual void afterUndelete(List<Sobject> undeletedRecords) { }
}

AccountTriggerHandler:

public with sharing class AccountTriggerHandler extends TriggerHandlerBase {
    protected override void beforeInsert(List<Sobject> newRecords) {
        List<Account> newAccounts = (List<Account>) newRecords;
    }

    protected override void beforeUpdate(Map<Id, Sobject> oldRecordsMap, Map<Id, Sobject> newRecordsMap) {
        Map<Id, Account> oldAccountsMap = (Map<Id, Account>) oldRecordsMap;
        Map<Id, Account> newAccountsMap = (Map<Id, Account>) newRecordsMap;

        // Do something with the Account records.
        // Use private methods in this class to handle the work or
        // delegate it to a service class.
    }

    // Use private methods to handle the heavy lifting
}

AccountTrigger :-

trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
    new AccountTriggerHandler().run();
}

uniquesymbol

Leave a Reply