Show:            

TriggerHandler

Trigger Handler virtual class as base for all trigger handlers
Signature
public virtual class TriggerHandler
See
Author
Since
  • 2013
  • Author
    Since
  • 2021
  • 2023-02-24 add andFinally method
  • 2023-09 method chaining
  • TriggerHandler Properties

    Name Signature Annotations Description
    BYPASS_ALL_ALIAS
    private static final String BYPASS_ALL_ALIAS
    @TestVisible
    This is the value that will be in the returned list or set when global bypass is active
    bypassedHandlers
    private static Set<String> bypassedHandlers
    @TestVisible
    All bypassed handlers
    ERROR_TRIGGERCONTEXT
    private static final String ERROR_TRIGGERCONTEXT
    @TestVisible
    Error text - assumes English for debug logs
    globalBypass
    private static Boolean globalBypass
    @TestVisible
    true if we bypass all triggers without checking the contents of bypassedHandlers
    handlerName
    private String handlerName
    The name of this handler. Set by getHandlerName()
    isTriggerExecuting
    private Boolean isTriggerExecuting
    @TestVisible
    Is this class executing in trigger context?
    loopCountMap
    private static Map<String, LoopCount> loopCountMap
    @TestVisible
    Map of handlerName => times run() was invoked
    showDebug
    private static Boolean showDebug
    @TestVisible
    true if we include a debug statement for trigger entry and exit
    showLimits
    private static Boolean showLimits
    @TestVisible
    true if we include a debug statement for limits
    triggerEvent
    private System.TriggerOperation triggerEvent
    @TestVisible
    The current triggerEvent of the trigger, overridable in tests

    TriggerHandler Constructors

    TriggerHandler()

    Basic constructor. Slower than the other one
    Signature
    public TriggerHandler()
    See
    Example
     new AccountSampleTriggerHandler().run(); 
      // (in Trigger Handler) 
     public AccountSampleTriggerHandler) { 
       super('AccountSampleTriggerHandler'); 
       this.newRecords = (List<Account>) Trigger.new; 
       this.oldRecords = (List<Account>) Trigger.old; 
       this.newRecordsMap = (Map<Id, Account>) Trigger.newMap; 
       this.oldRecordsMap = (Map<Id, Account>) Trigger.oldMap; 
     }

    TriggerHandler(handlerName)

    Constructor with handler name to improve performance
    Signature
    public TriggerHandler(String handlerName)
    Parameters
    handlerName
    Type: String
    The name of the handler
    Author
    Since
  • 2021
  • Example
     new AccountSampleTriggerHandler('AccountSampleTriggerHandler').run(); 
     // (in Trigger Handler) 
     public AccountSampleTriggerHandler('AccountSampleTriggerHandler') { 
       this.newRecords = (List<Account>) Trigger.new; 
       this.oldRecords = (List<Account>) Trigger.old; 
       this.newRecordsMap = (Map<Id, Account>) Trigger.newMap; 
       this.oldRecordsMap = (Map<Id, Account>) Trigger.oldMap; 
     }

    TriggerHandler Methods

    • afterDelete ()
      Virtual method for the implementing class to override
    • afterInsert ()
      Virtual method for the implementing class to override
    • afterUndelete ()
      Virtual method for the implementing class to override
    • afterUpdate ()
      Virtual method for the implementing class to override
    • andFinally ()
      andFinally is called in every context, regardless of Trigger context
      Credit to James Simone for this idea
    • beforeDelete ()
      Virtual method for the implementing class to override
    • beforeInsert ()
      Virtual method for the implementing class to override
    • beforeUpdate ()
      Virtual method for the implementing class to override
    • bypass (handlerName)
      Bypass by string
    • bypass (handlerType)
      Bypass by type/class. This is probably best for avoiding typos.
    • bypass (handlerNames)
      Bypass by list, e.g. TriggerHandler.bypass(listOfHandlerStrings)
    • bypassAll ()
      Bypass all handlers (clear bypassedHandlers to prevent confusion)
    • bypassList ()
      Return a list of the bypassed handlers
      Though both Set and List allow contains(value), we include both methods for convenience
    • bypassSet ()
      Return a Set of the bypassed handlers
      Though both Set and List allow contains(value), we include both methods for convenience
    • clearAllBypasses ()
      Clear all bypasses - by clearing the global bypass and by clearing the list of bypassed handlers
    • clearBypass (handlerName)
      Bypass a specific handler by name
    • clearBypass (handlerType)
      Bypass a specific handler by type
    • clearBypass (handlerNames)
      Bypass a list of handlers
    • clearBypassList ()
      Clear the entire bypass list, but keep the global bypass flag intact
      This is useful for resetting the list of handlers to bypass while maintaining global bypassing
    • clearGlobalBypass ()
      Clear only the global bypass flag, leaving the list of bypassed handlers intact
      This is useful for keeping a base set of bypassed handlers intact for an entire operation
    • clearMaxLoopCount ()
      Removes the limit for the number of times we allow this class to run
    • debug ()
      Instance method to show debug logs for just this trigger handler, allowing method chaining in the trigger.
    • debug (enabled)
      Instance method to show debug logs for just this trigger handler, allowing method chaining in the trigger.
    • getHandlerName ()
      Get the name of the current handler. This can be set by using the constructor with the string parameter to improve performance
    • getLoopCount (handlerName)
      return the current loop count
    • incrementCheckLoopCount ()
      Increment the loop count and check if we exceeded the max loop count.
      Silently exit if we have exceeded it. (Log to System.debug)
    • isBypassed (handlerName)
      A handler is considered bypassed if it was bypassed, or all handlers have been bypassed
    • isBypassed (handlerType)
      A handler is considered bypassed if it was bypassed, or all handlers have been bypassed
    • limits ()
      Instance method to show limits for just this trigger handler, allowing method chaining in the trigger.
    • limits (enabled)
      Instance method to show/hide limits for just this trigger handler, allowing method chaining in the trigger.
    • run ()
      Main method that will be called during execution
      See the sample trigger for the best way to set up your handler
    • setBypass (handlerName, desiredValue)
      Set bypass status to a specific value. Eliminates the need to know the current bypass status
    • setMaxLoopCount (max)
      Limit the number of times this handler can be run before it fails silently
      Returning TriggerHandler enables method chaining when used in a trigger
      Use this in the trigger or handler
    • setTriggerContext ()
      Base method called by constructor to set the current context
    • setTriggerContext (opType, testMode)
      Set the current trigger context based on the System.TriggerOperation
      If we are not in a trigger context, then we set isTriggerExecuting to false <r>A single line is not covered by tests because we do not "fool" the handler into thinking that Trigger.isExecuting is true when we are running our tests. This line would be covered by any trigger handler in the org (and is the reason we include a sample handler for assistance when creating a package for this project)
    • showDebug ()
      Called in the trigger to force the class to debug trigger entry and exit with context.
      Use this in the trigger or handler
    • showDebug (enabled)
      Called in the trigger to force the class to debug trigger entry and exit with context.
      Set to true to show entry and exit.
    • showLimits ()
      Called before the trigger to force the class to debug query limits when it runs.
      Use this in the trigger or handler
    • showLimits (enabled)
      Called before the trigger to enable the class to debug (or not) query limits when it runs.
      Set to true to show limits.
      Use this in the trigger or handler
    • validateRun ()
      Make sure this trigger should continue to run
      Returning false causes trigger handler to exit

    afterDelete()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void afterDelete()

    afterInsert()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void afterInsert()

    afterUndelete()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void afterUndelete()

    afterUpdate()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void afterUpdate()

    andFinally()

    andFinally is called in every context, regardless of Trigger context
    Credit to James Simone for this idea
    Signature
    @TestVisible
    protected virtual void andFinally()
    See
    Author
    James Simone
    Since
  • 2022
  • beforeDelete()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void beforeDelete()

    beforeInsert()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void beforeInsert()

    beforeUpdate()

    Virtual method for the implementing class to override
    Signature
    @TestVisible
    protected virtual void beforeUpdate()

    bypass(handlerName)

    Bypass by string
    Signature
    public static void bypass(String handlerName)
    Parameters
    handlerName
    Type: String
    Name of the handler to be bypassed
    Example
     TriggerHandler.bypass('AccountSampleTriggerHandler');

    bypass(handlerType)

    Bypass by type/class. This is probably best for avoiding typos.
    Signature
    public static void bypass(Type handlerType)
    Parameters
    handlerType
    Type: Type
    The Class to be bypassed. Must end with ".class"
    Author
    Example
     TriggerHandler.bypass(AccountTriggerHandler.class);

    bypass(handlerNames)

    Bypass by list, e.g. TriggerHandler.bypass(listOfHandlerStrings)
    Signature
    public static void bypass(List<String> handlerNames)
    Parameters
    handlerNames
    Type: List<String>
    List of handlernames

    bypassAll()

    Bypass all handlers (clear bypassedHandlers to prevent confusion)
    Signature
    public static void bypassAll()
    Example
     TriggerHandler.bypassAll();

    bypassList()

    Return a list of the bypassed handlers
    Though both Set and List allow contains(value), we include both methods for convenience
    Signature
    public static List<String> bypassList()
    Returns
    List<String> List of bypassed handlers
    Example
     TriggerHandler.bypassList();

    bypassSet()

    Return a Set of the bypassed handlers
    Though both Set and List allow contains(value), we include both methods for convenience
    Signature
    public static Set<String> bypassSet()
    Returns
    Set<String> Set of bypassed handlers
    Author
    David Schach
    Since
  • 2022
  • Example
     if(TriggerHandler.bypassSet().contains('AccountSampleTriggerHandler'){ 
       // do something 
     }

    clearAllBypasses()

    Clear all bypasses - by clearing the global bypass and by clearing the list of bypassed handlers
    Signature
    public static void clearAllBypasses()
    Example
     TriggerHandler.clearAllBypasses();

    clearBypass(handlerName)

    Bypass a specific handler by name
    Signature
    public static void clearBypass(String handlerName)
    Parameters
    handlerName
    Type: String
    The class name to be bypassed
    Author
    Example
     TriggerHandler.clearBypass('AccountSampleTriggerHandler');

    clearBypass(handlerType)

    Bypass a specific handler by type
    Signature
    public static void clearBypass(Type handlerType)
    Parameters
    handlerType
    Type: Type
    The class to be bypassed. Must end with ".class"
    Example
     TriggerHandler.clearBypass(AccountSampleTriggerHandler.class);

    clearBypass(handlerNames)

    Bypass a list of handlers
    Signature
    public static void clearBypass(List<String> handlerNames)
    Parameters
    handlerNames
    Type: List<String>
    List of Strings of handlers to bypass
    Example
     List<String> classList = ['AccountTriggerHandler','ContactTriggerHandler']; 
     TriggerHandler.clearBypass(classList);

    clearBypassList()

    Clear the entire bypass list, but keep the global bypass flag intact
    This is useful for resetting the list of handlers to bypass while maintaining global bypassing
    Signature
    public static void clearBypassList()
    Example
     TriggerHandler.clearBypassList();

    clearGlobalBypass()

    Clear only the global bypass flag, leaving the list of bypassed handlers intact
    This is useful for keeping a base set of bypassed handlers intact for an entire operation
    Signature
    public static void clearGlobalBypass()
    Example
     TriggerHandler.clearGlobalBypass();

    clearMaxLoopCount()

    Removes the limit for the number of times we allow this class to run
    Signature
    public void clearMaxLoopCount()

    debug()

    Instance method to show debug logs for just this trigger handler, allowing method chaining in the trigger.
    Signature
    public TriggerHandler debug()
    Returns
    TriggerHandler returning this class enables method chaining
    See
    Since
  • 2023
  • Example
     new AccountSampleTriggerHandler.debug().run();

    debug(enabled)

    Instance method to show debug logs for just this trigger handler, allowing method chaining in the trigger.
    Signature
    public TriggerHandler debug(Boolean enabled)
    Parameters
    enabled
    Type: Boolean
    true to enable; false to disable
    Returns
    TriggerHandler returning this class enables method chaining
    See
    Since
  • 2023
  • Example
     new AccountSampleTriggerHandler.debug().run();

    getHandlerName()

    Get the name of the current handler. This can be set by using the constructor with the string parameter to improve performance
    Signature
    @TestVisible
    private String getHandlerName()
    Returns
    String Name of the current handler
    See
    TriggerHandler.handlerName

    getLoopCount(handlerName)

    return the current loop count
    Signature
    public static Integer getLoopCount(String handlerName)
    Parameters
    handlerName
    Type: String
    The handler class to check for the current loop count
    Returns
    Integer How many times has this handler run?

    incrementCheckLoopCount()

    Increment the loop count and check if we exceeded the max loop count.
    Silently exit if we have exceeded it. (Log to System.debug)
    Signature
    private Boolean incrementCheckLoopCount()
    Returns
    Boolean Should the trigger continue execution?
    Authors

    isBypassed(handlerName)

    A handler is considered bypassed if it was bypassed, or all handlers have been bypassed
    Signature
    public static Boolean isBypassed(String handlerName)
    Parameters
    handlerName
    Type: String
    The class name of the handler we are checking is bypassed
    Returns
    Boolean Is this handler bypassed?
    Example
     TriggerHandler.isBypassed('AccountTriggerHandler');

    isBypassed(handlerType)

    A handler is considered bypassed if it was bypassed, or all handlers have been bypassed
    Signature
    public static Boolean isBypassed(Type handlerType)
    Parameters
    handlerType
    Type: Type
    The handler class we are checking is bypassed
    Returns
    Boolean Is this handler bypassed?
    Since
  • 2021
  • Example
     TriggerHandler.isBypassed(AccountTriggerHandler.class);

    limits()

    Instance method to show limits for just this trigger handler, allowing method chaining in the trigger.
    Signature
    public TriggerHandler limits()
    Returns
    TriggerHandler returning this class enables method chaining
    See
    Since
  • 2023
  • Example
     new AccountSampleTriggerHandler.limits().run();

    limits(enabled)

    Instance method to show/hide limits for just this trigger handler, allowing method chaining in the trigger.
    Signature
    public TriggerHandler limits(Boolean enabled)
    Parameters
    enabled
    Type: Boolean
    true to enable; false to disable
    Returns
    TriggerHandler returning this class enables method chaining
    See
    Since
  • 2023
  • Example
     new AccountSampleTriggerHandler.limits(false).run();

    run()

    Main method that will be called during execution
    See the sample trigger for the best way to set up your handler
    Signature
    public void run()
    Authors
    Example
     new AccountSampleTriggerHandler().run();

    setBypass(handlerName, desiredValue)

    Set bypass status to a specific value. Eliminates the need to know the current bypass status
    Signature
    public static void setBypass(String handlerName, Boolean desiredValue)
    Parameters
    handlerName
    Type: String
    The name of the TriggerHandler class
    desiredValue
    Type: Boolean
    true to bypass, and false to run the handler/clear the bypass
    Since
  • 2021
  • Author
    Example
     TriggerHandler.setBypass('AccountTriggerHandler', false); 
     -or- 
     Boolean isBypassed = TriggerHandler.isBypassed('AccountTriggerHandler'); 
     TriggerHandler.bypass('AccountTriggerHandler'); 
     // do something here 
     TriggerHandler.setBypass('AccountTriggerHandler', isBypassed);

    setMaxLoopCount(max)

    Limit the number of times this handler can be run before it fails silently
    Returning TriggerHandler enables method chaining when used in a trigger
    Use this in the trigger or handler
    Signature
    public TriggerHandler setMaxLoopCount(Integer max)
    Parameters
    max
    Type: Integer
    Naximum number of times
    Returns
    TriggerHandler enables method chaining
    Author
    Example
     this.setMaxLoopCount(5); // in handler 
     AccountTriggerHandler.setMaxLoopCount(5); // in handler 
     or 
     new TriggerHandler().setMaxLoopCount(5).run(); // in trigger

    setTriggerContext()

    Base method called by constructor to set the current context
    Signature
    @TestVisible
    private void setTriggerContext()

    setTriggerContext(opType, testMode)

    Set the current trigger context based on the System.TriggerOperation
    If we are not in a trigger context, then we set isTriggerExecuting to false <r>A single line is not covered by tests because we do not "fool" the handler into thinking that Trigger.isExecuting is true when we are running our tests. This line would be covered by any trigger handler in the org (and is the reason we include a sample handler for assistance when creating a package for this project)
    Signature
    @TestVisible
    private void setTriggerContext(System.TriggerOperation opType, Boolean testMode)
    Parameters
    opType
    Type: System.TriggerOperation
    The operation type - set automatically by the system
    testMode
    Type: Boolean
    Only used in test methods to force certain contexts
    See
    TriggerHandler.isTriggerExecuting

    showDebug()

    Called in the trigger to force the class to debug trigger entry and exit with context.
    Use this in the trigger or handler
    Signature
    public static void showDebug()
    See
    Author
    Since
  • 2021
  • Example
     TriggerHandler.showDebug(); 
     new AccountSampleTriggerHandler.run(); // in trigger 
     -or- 
     AccountSampleTriggerHandler.showDebug(); // in handler

    showDebug(enabled)

    Called in the trigger to force the class to debug trigger entry and exit with context.
    Set to true to show entry and exit.
    Signature
    public static void showDebug(Boolean enabled)
    Parameters
    enabled
    Type: Boolean
    true to enable; false to disable
    See
    Author
    Since
  • 2021
  • showLimits()

    Called before the trigger to force the class to debug query limits when it runs.
    Use this in the trigger or handler
    Signature
    public static void showLimits()
    See
    Example
     TriggerHandler.showLimits(); 
     new AccountSampleTriggerHandler.run(); 
     -or- 
     AccountSampleTriggerHandler.showLimits();

    showLimits(enabled)

    Called before the trigger to enable the class to debug (or not) query limits when it runs.
    Set to true to show limits.
    Use this in the trigger or handler
    Signature
    public static void showLimits(Boolean enabled)
    Parameters
    enabled
    Type: Boolean
    true to enable; false to disable
    See

    validateRun()

    Make sure this trigger should continue to run
    Returning false causes trigger handler to exit
    Signature
    @TestVisible
    private Boolean validateRun()
    Returns
    Boolean Is the run valid?
    Exceptions
    TriggerHandlerException
    See

    TriggerHandler.LoopCount

    Inner class for managing the loop count per handler
    Signature
    @TestVisible
    private class LoopCount

    TriggerHandler.LoopCount Properties

    Name Signature Description
    count
    private Integer count
    Number of times this handler has been run
    max
    private Integer max
    Maximum number of times this handler should be run

    TriggerHandler.LoopCount Constructors

    LoopCount()

    Standard constructor
    Default max to 5
    Default count to 0
    Signature
    public LoopCount()

    LoopCount(max)

    Constructor with specified max loops
    Signature
    public LoopCount(Integer max)
    Parameters
    max
    Type: Integer
    Max number of loops allowed

    TriggerHandler.LoopCount Methods

    exceeded()

    Determines if we're about to exceed the loop count.
    Signature
    public Boolean exceeded()
    Returns
    Boolean True if less than 0 or more than max.

    getCount()

    Returns the current loop count.
    Signature
    public Integer getCount()
    Returns
    Integer Current loop count.

    getMax()

    Returns the max loop count.
    Signature
    public Integer getMax()
    Returns
    Integer Max loop count.

    increment()

    Increment the internal counter returning the results of this.exceeded().
    Signature
    public Boolean increment()
    Returns
    Boolean true if count will exceed max count or is less than 0.

    setMax(max)

    Sets the max loop count
    Signature
    public void setMax(Integer max)
    Parameters
    max
    Type: Integer
    The integer to set max to.

    TriggerHandler.TriggerHandlerException

    Exception class
    Signature
    public class TriggerHandlerException extends Exception