Skip to content

Instantly share code, notes, and snippets.

@brandonmikeska
Last active February 10, 2017 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brandonmikeska/ad27c488d4a98d7c55c1ea84e8b9367e to your computer and use it in GitHub Desktop.
Save brandonmikeska/ad27c488d4a98d7c55c1ea84e8b9367e to your computer and use it in GitHub Desktop.
/**
* Class TriggerFactory
*
* Used to instantiate and execute Trigger Handlers associated with sObjects.
*/
public with sharing class TriggerFactory
{
// Generate unique executionId for debuging execution results
private static String executionId;
// Map to make sure each trigger handler only runs once
private static Map<sObjectType, Boolean> recursions = new Map<sObjectType, Boolean>();
/**
* Public static method to create and execute a trigger handler
*
* Arguments:
* - Schema.sObjectType soType - Object type to process (SObject.sObjectType)
*
* Throws a TriggerException if a handler has not been created.
*/
public static void createHandler(Schema.sObjectType soType)
{
// Get a handler appropriate to the object being processed
ITrigger handler = getHandler(soType);
// Execute the handler for the trigger
executionId = generateGUID();
if(isFirstRun(soTYpe)) {
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing... ');
execute(handler, soType);
} else {
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Not Excuting (Recursive call)... ');
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending... ');
}
/**
* private static method to control the execution of the handler
*
* Arguments:
* - ITrigger handler - A Trigger Handler to execute
* - Schema.sObjectType soType - Object type to process (SObject.sObjectType)
*/
private static void execute(ITrigger handler, Schema.sObjectType soType)
{
// Before Trigger
if (Trigger.isBefore)
{
// Call the bulk before to handle any caching of data and enable bulkification
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Bulk Before. SOQL Count - ' + Limits.getQueries());
handler.bulkBefore();
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Bulk Before. SOQL Count - ' + Limits.getQueries());
// Iterate through the records to be deleted passing them to the handler.
if (Trigger.isDelete)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Before Delete. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.old)
{
handler.beforeDelete(so);
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Before Delete. SOQL Count - ' + Limits.getQueries());
}
// Iterate through the records to be inserted passing them to the handler.
else if (Trigger.isInsert)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Before Insert. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.new)
{
handler.beforeInsert(so);
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Before Insert. SOQL Count - ' + Limits.getQueries());
}
// Iterate through the records to be updated passing them to the handler.
else if (Trigger.isUpdate)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Before Update. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.old)
{
handler.beforeUpdate(so, Trigger.newMap.get(so.Id));
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Before Update. SOQL Count - ' + Limits.getQueries());
}
}
else
{
// Call the bulk after to handle any caching of data and enable bulkification
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Bulk After. SOQL Count - ' + Limits.getQueries());
handler.bulkAfter();
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Bulk After. SOQL Count - ' + Limits.getQueries());
// Iterate through the records deleted passing them to the handler.
if (Trigger.isDelete)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing After Delete. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.old)
{
handler.afterDelete(so);
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending After Delete. SOQL Count - ' + Limits.getQueries());
}
// Iterate through the records inserted passing them to the handler.
else if (Trigger.isInsert)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing After Insert. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.new)
{
handler.afterInsert(so);
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending After Delete. SOQL Count - ' + Limits.getQueries());
}
// Iterate through the records updated passing them to the handler.
else if (Trigger.isUpdate)
{
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing After Update. SOQL Count - ' + Limits.getQueries());
for (SObject so : Trigger.old)
{
handler.afterUpdate(so, Trigger.newMap.get(so.Id));
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending After Delete. SOQL Count - ' + Limits.getQueries());
}
}
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Executing Final Function. SOQL Count - ' + Limits.getQueries());
// Perform any post processing
handler.andFinally();
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Final Function. Overal SOQL Count - ' + Limits.getQueries());
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Final Function. Overal SOQL MAX LIMIT - ' + Limits.getLimitQueries());
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Final Function. Overal DML Count - ' + Limits.getDMLRows());
System.DEBUG('[TF | ' + soType + '] - ' + executionId + ': Ending Final Function. Overal DML MAX LIMIT - ' + Limits.getLimitDMLRows());
}
/**
* private static method to get the appropriate handler for the object type.
*
* Arguments:
* - Schema.sObjectType soType - Object type to locate (SObject.sObjectType)
*
* Returns: ITrigger - A trigger handler if one exists or null.
*/
private static ITrigger getHandler(Schema.sObjectType soType)
{
try {
return (ITrigger)Type.forName(soType.getDescribe().getName() + 'TriggerHandler').newInstance();
} catch(Exception e) {
throw new TriggerException('No Trigger Handler registered for Object Type: ' + soType);
}
}
/**
* private static method to generate a unique GUID for grouping DEBUG Logs.
*
* Arguments: NA
*
* Returns: String in a GUID format
*/
private static String generateGUID()
{
Blob b = Crypto.GenerateAESKey(128);
String h = EncodingUtil.ConvertTohex(b);
return h.SubString(0,8)+ '-' + h.SubString(8,12) + '-' + h.SubString(12,16) + '-' + h.SubString(16,20) + '-' + h.substring(20);
}
/**
* private static method to make sure the each trigger handler only runs once
*
* Arguments:
* - Schema.sObjectType soType - Object type to locate (SObject.sObjectType)
*
* Returns: True or False identify if the trigger handler has already ran
*/
private static Boolean isFirstRun(Schema.sObjectType soType) {
if(!recursions.containsKey(soType)) {
recursions.put(soType, true);
return true;
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment