Trigger Framework
To address the following problems we need to use a trigger framework instead of cramming all logic inside triggers:
- It is very difficult to maintain and debug code that is not structured according to OOP principles
- We should create abstractions of common logic
- We should have one trigger per object
- It is not possible to deactivate triggers in Production (without doing a deployment from a sandbox)
The following framework makes use of an optional Custom Metadata Type called TriggerSetting that controls whether a trigger is active. See the sub-section entitled "Trigger Setting" for more.
/**
* Central trigger handler
* This class must be extended and implemented for all trigger handlers
*/
public virtual class TriggerHandler {
protected virtual void onBeforeInsert() {}
protected virtual void onBeforeUpdate() {}
protected virtual void onBeforeDelete() {}
protected virtual void onAfterInsert() {}
protected virtual void onAfterUpdate() {}
protected virtual void onAfterDelete() {}
protected virtual void onAfterUndelete() {}
/**
* Invokes the appropriate handler method based on the triggering event
* Skips the trigger if TriggerSettings has this trigger set to inactive
*/
public void run() {
if (!isTriggerActive()) return;
if (Trigger.isBefore && Trigger.isInsert) onBeforeInsert();
else if (Trigger.isBefore && Trigger.isUpdate) onBeforeUpdate();
else if (Trigger.isBefore && Trigger.isDelete) onBeforeDelete();
else if (Trigger.isAfter && Trigger.isInsert) onAfterInsert();
else if (Trigger.isAfter && Trigger.isUpdate) onAfterUpdate();
else if (Trigger.isAfter && Trigger.isDelete) onAfterDelete();
else if (Trigger.isAfter && Trigger.isUndelete) onAfterUndelete();
}
private Boolean isTriggerActive() {
// check TriggerSetting__mdt to see if the Active__c flag is set for this trigger
}
}To implement a handler for a trigger, extend the above class and implement any method that is needed, like so:
public class AccountTriggerHandler extends TriggerHandler {
protected override void onBeforeUpdate() {
// before-update logic
}
}The trigger would then be reduced to a single line, as follows:
trigger AccountTrigger on Account (
before insert, before update, before delete, after insert, after update, after delete, after undelete) {
new AccountTriggerHandler().run();
}Trigger Setting
Trigger Setting
A standard configuration for this Custom Metadata Type can have the following fields:
- Label: Object Trigger (e.g. Account Trigger)
- Name: Object Name (e.g. Account)
- Active__c: checkbox (default checked)
