@@ -8,46 +8,82 @@ public abstract class TriggerHandler {
88 }
99 public TriggerContext context ; // The current context of the trigger
1010
11+ private String className ;
1112 private Integer hashCode ; // The hash code for the current records
1213 private Boolean isTriggerExecuting ; // Checks if the code was called by a trigger
14+ private TriggerSettings__c triggerSettings ;
1315
1416 protected TriggerHandler () {
17+ this .getClassName ();
18+ this .getTriggerSettings ();
19+
20+ this .addDebugStatement (' Initializing ' + this .className );
1521 this .setTriggerContext ();
1622 this .validateTriggerContext ();
1723 this .setHashCode ();
1824 }
1925
2026 public void execute () {
21- String sobjectType = Trigger .new == null ? Trigger .old .getSObjectType () : Trigger .new .getSObjectType ();
22- System .debug (' Starting execute method for: ' + sobjectType );
23- System .debug (' Hash codes already processed: ' + TriggerHandler .hashCodesForProcessedRecords );
24- System .debug (' Hash code for current records: ' + this .hashCode );
25- System .debug (' Trigger context for current records: ' + this .context );
26- System .debug (' Number of current records: ' + Trigger .size );
27+ this .addDebugStatement (' Execute method called for ' + this .className );
28+ // Check the custom setting. If it's disabled, stop everything, show's over
29+ // You don't have to go home but you can't stay here
30+ if (! shouldExecuteTriggers ()) {
31+ this .addDebugStatement (' Skipping execution of class ' + this .className );
32+ return ;
33+ }
34+
35+ this .addDebugStatement (this .className + ' is enabled, proceeding with execution' );
36+
37+ String sobjectType = Trigger .new == null ? String .valueOf (Trigger .old .getSObjectType ()) : String .valueOf (Trigger .new .getSObjectType ());
38+ this .addDebugStatement (' Starting execute method for: ' + sobjectType );
39+ this .addDebugStatement (' Hash codes already processed: ' + TriggerHandler .hashCodesForProcessedRecords );
40+ this .addDebugStatement (' Hash code for current records: ' + this .hashCode );
41+ this .addDebugStatement (' Trigger context for current records: ' + this .context );
42+ this .addDebugStatement (' Number of current records: ' + Trigger .size );
2743
2844 if (this .haveRecordsAlreadyBeenProcessed ()) {
29- System . debug (' Records already processed for this context, skipping' );
45+ this . addDebugStatement (' Records already processed for this context, skipping' );
3046 return ;
31- } else System .debug (' Records have not been processed for this context, continuing' );
47+ } else this .addDebugStatement (' Records have not been processed for this context, continuing' );
48+
49+ if (this .context == TriggerContext .BEFORE_INSERT ) this .executeBeforeInsert (Trigger .new );
50+ else if (this .context == TriggerContext .BEFORE_UPDATE ) this .executeBeforeUpdate (Trigger .new , Trigger .newMap , Trigger .old , Trigger .oldMap );
51+ else if (this .context == TriggerContext .BEFORE_DELETE ) this .executeBeforeDelete (Trigger .old , Trigger .oldMap );
52+ else if (this .context == TriggerContext .AFTER_INSERT ) this .executeAfterInsert (Trigger .new , Trigger .newMap );
53+ else if (this .context == TriggerContext .AFTER_UPDATE ) this .executeAfterUpdate (Trigger .new , Trigger .newMap , Trigger .old , Trigger .oldMap );
54+ else if (this .context == TriggerContext .AFTER_DELETE ) this .executeAfterDelete (Trigger .old , Trigger .oldMap );
55+ else if (this .context == TriggerContext .AFTER_UNDELETE ) this .executeAfterUndelete (Trigger .new , Trigger .newMap );
56+ }
3257
33- if ( this . context == TriggerContext . BEFORE_INSERT ) this . beforeInsert ( Trigger . new );
34- else if ( this . context == TriggerContext . BEFORE_UPDATE ) this . beforeUpdate ( Trigger . new , Trigger . newMap , Trigger . old , Trigger . oldMap );
35- else if ( this . context == TriggerContext . BEFORE_DELETE ) this . beforeDelete ( Trigger . old , Trigger . oldMap );
36- else if ( this . context == TriggerContext . AFTER_INSERT ) this . afterInsert ( Trigger . new , Trigger . newMap );
37- else if ( this . context == TriggerContext . AFTER_UPDATE ) this . afterUpdate ( Trigger . new , Trigger . newMap , Trigger . old , Trigger . oldMap );
38- else if ( this . context == TriggerContext . AFTER_DELETE ) this . afterDelete ( Trigger . old , Trigger . oldMap );
39- else if ( this . context == TriggerContext . AFTER_UNDELETE ) this . afterUndelete ( Trigger . new , Trigger . newMap );
58+ protected virtual void executeBeforeInsert ( List < SObject > newRecordList ) {}
59+ protected virtual void executeBeforeUpdate ( List < SObject > updatedRecordList , Map < Id , SObject > updatedRecordMap , List < SObject > oldRecordList , Map < Id , SObject > oldRecordMap ) {}
60+ protected virtual void executeBeforeDelete ( List < SObject > deletedRecordList , Map < Id , SObject > deletedRecordMap ) {}
61+ protected virtual void executeAfterInsert ( List < SObject > newRecordList , Map < Id , SObject > newRecordMap ) {}
62+ protected virtual void executeAfterUpdate ( List < SObject > updatedRecordList , Map < Id , SObject > updatedRecordMap , List < SObject > oldRecordList , Map < Id , SObject > oldRecordMap ) {}
63+ protected virtual void executeAfterDelete ( List < SObject > deletedRecordList , Map < Id , SObject > deletedRecordMap ) {}
64+ protected virtual void executeAfterUndelete ( List < SObject > undeletedRecordList , Map < Id , SObject > undeletedRecordMap ) {}
4065
41- this .runDmlForRelatedRecords ();
66+ private void getClassName () {
67+ this .className = String .valueOf (this ).split (' :' )[0 ];
4268 }
4369
44- protected virtual void beforeInsert (List < SObject > newRecordList ) {}
45- protected virtual void beforeUpdate (List < SObject > updatedRecordList , Map < Id , SObject > updatedRecordMap , List < SObject > oldRecordList , Map < Id , SObject > oldRecordMap ) {}
46- protected virtual void beforeDelete (List < SObject > deletedRecordList , Map < Id , SObject > deletedRecordMap ) {}
47- protected virtual void afterInsert (List < SObject > newRecordList , Map < Id , SObject > newRecordMap ) {}
48- protected virtual void afterUpdate (List < SObject > updatedRecordList , Map < Id , SObject > updatedRecordMap , List < SObject > oldRecordList , Map < Id , SObject > oldRecordMap ) {}
49- protected virtual void afterDelete (List < SObject > deletedRecordList , Map < Id , SObject > deletedRecordMap ) {}
50- protected virtual void afterUndelete (List < SObject > undeletedRecordList , Map < Id , SObject > undeletedRecordMap ) {}
70+ private void getTriggerSettings () {
71+ this .triggerSettings = TriggerSettings__c .getInstance ();
72+
73+ if (this .triggerSettings .Id == null ) {
74+ // If there's no ID, then there are settings setup for the current user at the user, profile or org level
75+ // Upsert the org defaults - the default field values will be used
76+ upsert TriggerSettings__c .getOrgDefaults ();
77+ // Call getInstance() again to get the settings with the field defaults
78+ this .triggerSettings = TriggerSettings__c .getInstance ();
79+ }
80+ }
81+
82+ private void addDebugStatement (String debugStatement ) {
83+ if (! this .triggerSettings .EnableDebugging__c ) return ;
84+
85+ System .debug (debugStatement );
86+ }
5187
5288 private void setTriggerContext () {
5389 this .isTriggerExecuting = Trigger .isExecuting ;
@@ -64,7 +100,19 @@ public abstract class TriggerHandler {
64100
65101 private void validateTriggerContext () {
66102 String errorMessage = ' Trigger handler called outside of trigger execution' ;
67- if (! this .isTriggerExecuting || this .context == null ) throw new Exceptions .TriggerHandlerException (errorMessage );
103+ if (! this .isTriggerExecuting || this .context == null ) throw new TriggerHandlerException (errorMessage );
104+ }
105+
106+ private Boolean shouldExecuteTriggers () {
107+ this .addDebugStatement (' triggerSettings.ExecuteTriggers__c=' + this .triggerSettings .ExecuteTriggers__c );
108+
109+ String handlerClassesToSkipString = this .triggerSettings .HandlerClassesToSkip__c ;
110+ if (handlerClassesToSkipString == null ) handlerClassesToSkipString = ' ' ;
111+ Set <String > handlerClassesToSkip = new Set <String >(handlerClassesToSkipString .toLowerCase ().split (' \n ' ));
112+ this .addDebugStatement (' triggerSettings.HandlerClassesToSkip__c=' + this .triggerSettings .HandlerClassesToSkip__c );
113+
114+ // If ExecuteTriggers == true and the current class isn't in the list of handlers to skip, then execute
115+ return this .triggerSettings .ExecuteTriggers__c && ! handlerClassesToSkip .contains (this .className .toLowerCase ());
68116 }
69117
70118 private void setHashCode () {
@@ -111,4 +159,6 @@ public abstract class TriggerHandler {
111159 }
112160 }
113161
162+ private class TriggerHandlerException extends Exception {}
163+
114164}
0 commit comments