高章伟
2022-02-18 8b5f4c6c281cfa548f92de52c8021e37aa81901e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 https://github.com/kevinohara80/sfdc-trigger-framework
*/
public virtual class Oly_TriggerHandler {
    private static Set<String> 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<String>();
    }
 
    // 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 {}
}