Trigger Factory

TriggerFactory in Salesforce Apex | The Developer Guide

Trigger structures in Apex are something clever. We as a whole realize we need them, we as a whole realize that it is best practice to eliminate rationale from the actual triggers for a few reasons (examined beneath), and we as a whole understand what a torment it is to unit test code sitting straightforwardly in a trigger

I expected to set up a trigger structure for another client two or three weeks prior. Being the inventive, skilled engineer that I am, my first port of call was, obviously, Google. Why reproduce the wheel? There are heaps of these structures around.

Use of Trigger Framework

A trigger overseer system is an approach to eliminate rationale from your triggers and authorize consistency across the stage. The actual system will do the truly difficult work for you regarding sorting out which sort of trigger is at present running and terminating the right rationale. 

Here is a portion of the benefits of utilizing a trigger structure: 

  • Eliminating trigger rationale from the trigger makes unit testing and upkeep a lot simpler. 
  • Normalizing triggers implies the entirety of your triggers works in a reliable manner. 
  • A solitary trigger for every item provides full power over the request of execution
  • The anticipation of trigger recursion

It makes it simple for huge groups of engineers to work across an organization with loads of triggers. I as of late worked on an organization that had triggers on around fifty articles, and the way that each trigger was executed in a predictable way made it simple to go in and make changes or add new triggers

A trigger system is a good thought in the event that you have more than one engineer working in your organization. It empowers the lead/engineer to characterize how every trigger in the application should work. Utilizing a system permits the planner to settle on choices, for example, "each trigger should execute a custom setting which permits us to turn the trigger off". Or on the other hand maybe the engineer needs to guarantee that any approval which happens in a trigger should be actualized by a technique called "Approve()" on the trigger controller for consistency. I've dealt with organizations where various designers have their own particular manner of executing triggers, and it makes troubleshooting incredibly troublesome when one trigger has 1000 lines of code in it, doing 20 distinct errands.

dont miss out iconDon't forget to check out: Invoke Apex Class From JavaScript Button in Salesforce

Trigger Framework Requirements

Since I've groaned about every other person's systems, here's my attempt at something a digit less difficult. 

  • The structure ought to be straightforward. Any engineer ought to have the option to perceive how the structure functions without pursuing a heap of standard code and remarks. 
  • A solitary overseer for each object to deal with all occasions in bulkified structure (no requirement for single record usage). 
  • An interface for the trigger controllers to uphold consistency. 
  • No mind-boggling trigger production line rationale, we'll utilize some fundamental reliance infusion all things considered. 
  • Need the capacity to turn off triggers. This capacity should be upheld on each trigger. 
  • Starting execution of the system on another organization should be amazingly straightforward. 
  • In spite of the system being lightweight, it should be extensible so it tends to be added to as the prerequisites of the organization develop.
  • Designers just need to stress over composing their trigger controller class. They shouldn't have to need to change or even comprehend the hidden rationale of the actual structure (no compelling reason to put another IF explanation in a TriggerHanderFactory class, for instance).

Interface for trigger

The interface directs which techniques each trigger controller should execute, regardless of whether these strategies have no code in them. By actualizing the strategies in this class, the TriggerFactory (talked about underneath) can be sure that the trigger controller has a technique for every one of these occasions: 

  • Before/After Insert
  • Before/After Update
  • Before/After Delete
  • After Undelete
  • IsDisabled
public interface ITriggerHandler{
    void BeforeInsert(List<SObject> newRecord); 
    void BeforeUpdate(Map<Id, SObject> newRecord, Map<Id, SObject> oldItems); 
    void BeforeDelete(Map<Id, SObject> oldRecord); 
    void AfterInsert(Map<Id, SObject> newRecord); 
    void AfterUpdate(Map<Id, SObject> newRecord, Map<Id, SObject> oldRecord); 
    void AfterDelete(Map<Id, SObject> oldRecord); 
    void AfterUndelete(Map<Id, SObject> oldRecord); 
    Boolean IsDisabled();  
}

The Trigger Factory

public class TriggerDispatcher {
    public static void Run(ITriggerHandler handler) {
        if (handler.IsDisabled())
        return;
        if (Trigger.IsBefore ){
            if (Trigger.IsInsert)
            handler.BeforeInsert(trigger.new);
            if (Trigger.IsUpdate)
            handler.BeforeUpdate(trigger.newMap, trigger.oldMap); 
            if (Trigger.IsDelete)
            handler.BeforeDelete(trigger.oldMap);
        }         
        // After trigger logic
        if (Trigger.IsAfter) {
            if (Trigger.IsInsert)
            handler.AfterInsert(Trigger.newMap);
            if (Trigger.IsUpdate)
            handler.AfterUpdate(trigger.newMap, trigger.oldMap);
            if (trigger.IsDelete)
            handler.AfterDelete(trigger.oldMap);
            if (trigger.isUndelete)
            handler.AfterUndelete(trigger.oldMap);
        }
    }
}

Trigger Handler

public class AccountTriggerHandler implements ITriggerHandler{   
    public static Boolean TriggerDisabled = false; 
    public Boolean IsDisabled(){
        if (TriggerSettings__c.AccountTriggerDisabled__c = true)
        return true;
        else
        return TriggerDisabled;
    }
    public void BeforeInsert(List<SObject> newItems){
        for (Account acc : (List<Account>)newItems){
            if (acc.Name.contains('test'))
            acc.Name.addError('You may not use the word "test" in the account name');
        }
    }
    public void BeforeUpdate(Map<Id, SObject> newItems, Map<Id, SObject> oldItems) {}
    public void BeforeDelete(Map<Id, SObject> oldItems) {}
    public void AfterInsert(Map<Id, SObject> newItems) {}
    public void AfterUpdate(Map<Id, SObject> newItems, Map<Id, SObject> oldItems) {} 
    public void AfterDelete(Map<Id, SObject> oldItems) {}
    public void AfterUndelete(Map<Id, SObject> oldItems) {}
}

dont miss out iconCheck out another amazing blog by Aditya here: Lightning DataTable in Salesforce | The Developer Guide

Apex Trigger

trigger AccountTrigger on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete)
{
    if(checkRecursive.runOnce()){
        TriggerDispatcher.Run(new AccountTriggerHandler());
    }
}

Stop Recursive Trigger

public Class checkRecursive {
    private static boolean run = 0;
    public static boolean runOnce() {
        if(run<2) {
            run=run=1;
            return true;
        } else {
            return run;
        }
    }
}

 

triggerfactory

Responses

Popular Salesforce Blogs