Skip to content

Instantly share code, notes, and snippets.

@cyberjus
Created November 26, 2012 15:11
Show Gist options
  • Save cyberjus/4148705 to your computer and use it in GitHub Desktop.
Save cyberjus/4148705 to your computer and use it in GitHub Desktop.
SFDC Trigger Template
trigger Account_Trigger on Account (after delete, after insert, after undelete,
after update, before delete, before insert, before update) {
TriggerManager.execute('AccountTriggerHandler');
}
public class AccountTriggerHandler extends TriggerHandler {
// Build method to bind events to functions
public void build() {
System.debug('Build Account Trigger');
bind(TriggerManager.Evt.AfterUpdate, new AccountAfterUpdateHandler());
bind(TriggerManager.Evt.AfterUpdate, new UpdateAccount());
}
/**
Subclasses to define what functions to run
*/
// TEMP
private class AccountAfterUpdateHandler extends TriggerHandler.TriggerFunction {
public void main() {
System.debug('Trigger Items' + Trigger.new);
System.debug(LoggingLevel.INFO, 'After Update handling ' + Trigger.new );
List<Contact> contacts = new List<Contact>([select Id, Title from Contact where AccountId in :Trigger.new]);
for (Contact c : contacts) {
c.Title = 'Fact Checker';
}
update contacts;
}
}
// TEMP
private class UpdateAccount extends TriggerHandler.TriggerFunction {
public void main() {
List<Account> accounts = new List<Account>();
for (SObject so : Trigger.new) {
Account account = (Account)so;
Account updateAccount = new Account(Id = account.Id);
updateAccount.Description = 'This is a test';
System.debug('I updated the account');
accounts.add(updateAccount);
}
unbind(TriggerManager.Evt.AfterUpdate);
update accounts;
}
}
}
public with sharing abstract class TriggerHandler {
// Internal mapping of handlers
Map<String, List<TriggerFunction>> eventFunctionMapping = new Map<String, List<TriggerFunction>>();
// Force build on handler creation
public TriggerHandler() {
build();
}
// Abstract Method to be implemented by Object Handlers
abstract void build();
// Bind functions to events
public void bind(TriggerManager.Evt e, TriggerFunction f) {
List<TriggerFunction> functions = eventFunctionMapping.get(e.name());
if (functions == null) {
functions = new List<TriggerFunction>();
eventFunctionMapping.put(e.name(), functions);
}
functions.add(f);
}
// Unbind a function from the handler
public void unbind(TriggerManager.Evt e, TriggerFunction f) {
List<TriggerFunction> functions = eventFunctionMapping.get(e.name());
if (functions != null) {
for (Integer i = 0; i <= functions.size(); i++) {
if (functions.get(i) == f) {
functions.remove(i);
}
}
}
}
// Invokes correct handlers as per the context of trigger and available registered handlers
public void run() {
TriggerManager.Evt e = null;
if(Trigger.isInsert && Trigger.isBefore){
e = TriggerManager.Evt.BeforeInsert;
} else if(Trigger.isInsert && Trigger.isAfter){
e = TriggerManager.Evt.AfterInsert;
} else if(Trigger.isUpdate && Trigger.isBefore){
e = TriggerManager.Evt.BeforeUpdate;
} else if(Trigger.isUpdate && Trigger.isAfter){
e = TriggerManager.Evt.AfterUpdate;
} else if(Trigger.isDelete && Trigger.isBefore){
e = TriggerManager.Evt.BeforeDelete;
} else if(Trigger.isDelete && Trigger.isAfter){
e = TriggerManager.Evt.AfterDelete;
} else if(Trigger.isUndelete){
e = TriggerManager.Evt.AfterUndelete;
}
List<TriggerFunction> functions = eventFunctionMapping.get(e.name());
if (functions != null && !functions.isEmpty()) {
// Run each applicable function
for (TriggerFunction f : functions.clone()) {
f.main(this); // Inject handler to the function
}
}
}
// Base Trigger Function. To be bound to events.
public abstract class TriggerFunction {
TriggerHandler handler;
// Main method injection to add the handler
public void main(TriggerHandler h) {
handler = h;
main();
}
// Main Method that must be implemented by Trigger Functions
abstract void main();
// Remove this function from the handler for an event
protected void unbind(TriggerManager.Evt e) {
handler.unbind(e, this);
}
}
}
public with sharing class TriggerManager {
// Enum representing each of before/after CRUD events on Sobjects
public enum Evt {
AfterDelete, AfterInsert, AfterUndelete,
AfterUpdate, BeforeDelete, BeforeInsert, BeforeUpdate
}
// Map of what handlers we have registered with their functions already
static Map<String, TriggerHandler> handlers = new Map<String, TriggerHandler>();
// Static method called from trigger event
public static void execute(String name) {
// Get handler from registered list
TriggerHandler handler = handlers.get(name);
// Check if handler not registered
if (handler == null) {
handler = createHandler(name);
// Make sure we find a handler
if (handler == null) {
throw new TriggerHandlerException('No Trigger Handler registered for : ' + name);
}
handlers.put(name, handler);
}
// Run trigger handler
handler.run();
}
// Private static method to get the appropriate handler for the object type.
private static TriggerHandler createHandler(String name) {
Type t = Type.forName(name);
return (TriggerHandler) t.newInstance();
}
// Trigger Exception
public class TriggerHandlerException extends Exception {}
}
@cyberjus
Copy link
Author

@abhinavguptas
Copy link

Looks fine to me, more of a personal taste on how we want to go around it. Few suggestions

  • TriggerManager is TriggerExecutor actually, as its not managing anything
  • TriggerHandler could be using Builder pattern, so this would lead to a TriggerBuilder with a Trigger instance ready to be executed by TriggerExecutor http://en.wikipedia.org/wiki/Builder_pattern#Java
  • main() is a starting class function name in Java, so being from that background it looks confusing to me.
  • We don't need dynamic type initalization here, as we can change TriggerManager.execute (String) to TriggerManager.execute(TriggerHandler) and Account trigger can easily call TriggerManager.execute(new AccountTriggerHandler()), this will retain references correctly between classes ( a problem with dynamic string based initalizations).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment