/* https://github.com/kevinohara80/sfdc-trigger-framework */ public virtual class Oly_TriggerHandler { private static Set bypassedHandlers; // the current context of the trigger, overridable in tests @TestVisible private TriggerContext context; // the current context of the trigger, overridable in tests @TestVisible private Boolean isTriggerExecuting; // static initialization static { bypassedHandlers = new Set(); } // constructor public Oly_TriggerHandler() { this.setTriggerContext(); } /*************************************** * public instance methods ***************************************/ // main method that will be called during execution public void run() { if(!validateRun()) return; // dispatch to the correct handler method if(this.context == TriggerContext.BEFORE_INSERT) { this.beforeInsert(); } else if(this.context == TriggerContext.BEFORE_UPDATE) { this.beforeUpdate(); } else if(this.context == TriggerContext.BEFORE_DELETE) { this.beforeDelete(); } else if(this.context == TriggerContext.AFTER_INSERT) { this.afterInsert(); } else if(this.context == TriggerContext.AFTER_UPDATE) { this.afterUpdate(); } else if(this.context == TriggerContext.AFTER_DELETE) { this.afterDelete(); } else if(this.context == TriggerContext.AFTER_UNDELETE) { this.afterUndelete(); } } /*************************************** * public static methods ***************************************/ public static void bypass(String handlerName) { Oly_TriggerHandler.bypassedHandlers.add(handlerName); } public static void clearBypass(String handlerName) { Oly_TriggerHandler.bypassedHandlers.remove(handlerName); } public static Boolean isBypassed(String handlerName) { return Oly_TriggerHandler.bypassedHandlers.contains(handlerName); } public static void clearAllBypasses() { Oly_TriggerHandler.bypassedHandlers.clear(); } /*************************************** * private instancemethods ***************************************/ @TestVisible private void setTriggerContext() { this.setTriggerContext(null, false); } @TestVisible private void setTriggerContext(String ctx, Boolean testMode) { if (!Trigger.isExecuting && !testMode) { this.isTriggerExecuting = false; return; } else { this.isTriggerExecuting = true; } if ((Trigger.isExecuting && Trigger.isBefore && Trigger.isInsert) || (ctx != null && ctx == 'before insert')) { this.context = TriggerContext.BEFORE_INSERT; } else if ((Trigger.isExecuting && Trigger.isBefore && Trigger.isUpdate) || (ctx != null && ctx == 'before update')){ this.context = TriggerContext.BEFORE_UPDATE; } else if ((Trigger.isExecuting && Trigger.isBefore && Trigger.isDelete) || (ctx != null && ctx == 'before delete')) { this.context = TriggerContext.BEFORE_DELETE; } else if ((Trigger.isExecuting && Trigger.isAfter && Trigger.isInsert) || (ctx != null && ctx == 'after insert')) { this.context = TriggerContext.AFTER_INSERT; } else if ((Trigger.isExecuting && Trigger.isAfter && Trigger.isUpdate) || (ctx != null && ctx == 'after update')) { this.context = TriggerContext.AFTER_UPDATE; } else if ((Trigger.isExecuting && Trigger.isAfter && Trigger.isDelete) || (ctx != null && ctx == 'after delete')) { this.context = TriggerContext.AFTER_DELETE; } else if ((Trigger.isExecuting && Trigger.isAfter && Trigger.isUndelete) || (ctx != null && ctx == 'after undelete')) { this.context = TriggerContext.AFTER_UNDELETE; } } // make sure this trigger should continue to run @TestVisible private Boolean validateRun() { if (!this.isTriggerExecuting || this.context == null) { throw new Oly_TriggerHandlerException('Trigger handler called outside of Trigger execution'); } if (Oly_TriggerHandler.bypassedHandlers.contains(getHandlerName())) { return false; } return true; } @TestVisible private String getHandlerName() { System.debug('getHandlerName -> ' + String.valueOf(this)); return String.valueOf(this).substring(0, String.valueOf(this).indexOf(':')); } /*************************************** * context methods ***************************************/ // context-specific methods for override @TestVisible protected virtual void beforeInsert(){} @TestVisible protected virtual void beforeUpdate(){} @TestVisible protected virtual void beforeDelete(){} @TestVisible protected virtual void afterInsert(){} @TestVisible protected virtual void afterUpdate(){} @TestVisible protected virtual void afterDelete(){} @TestVisible protected virtual void afterUndelete(){} /*************************************** * inner classes ***************************************/ @TestVisible private enum TriggerContext { BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, AFTER_UNDELETE } // exception class public class Oly_TriggerHandlerException extends Exception {} }