Tuesday, July 11, 2017

Trigger and it's handler class example with design pattern.

Please check my previous post (Trigger and it's handler class structure for your organisation.), where I mentioned the architectural structure to design or handle trigger for your organisation.

For the same you should have the below apex classes and trigger,

1. TriggerHandlerException class [Handled exception].
2. TriggerHandler class [An abstract class where all trigger related operations have been structured as a template].
3. TriggerFactory class [Factory of Concrete Trigger Handler classes].
4. TriggerWorker class [This is the worker class for trigger. Each and every trigger just call "executeTrigger()" method of this worker class].
5. ConcreteTriggerHandler class [This is the main handler class, where the actual logic will be define and this class extend TriggerHandler abstract class and defined all abstract method].
6. Trigger for an SObject [From here only call the "executeTrigger()" method of this TriggerWorker class with string parameter as "ConcreteTriggerHandler class name"].


Suppose we want to create a trigger of Account object, then the source code will be as follows,

1. TriggerHandlerException
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2017
 *
 * Description : This is custom exception calss and fire while trying to create an
 * handler instance which is not registered.
 *.
 */
public class TriggerHandlerException extends Exception {}

2. TriggerHandler
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This abstract class is responsible to create a template to handle trigger operations.
 *               All Trigger Handlers must implement to enforce best practice.
 */
public abstract class TriggerHandler{
    //Template method
    public void doExecute(){
        // Before Trigger
        if (Trigger.isBefore){
            // Iterate through the records to be deleted passing them to the handler.
            if (Trigger.isDelete)
            {
                beforeDelete(Trigger.old, Trigger.oldMap);
            }
            // Iterate through the records to be inserted passing them to the handler.
            else if (Trigger.isInsert)
            {
                beforeInsert(Trigger.new);
            }
            // Iterate through the records to be updated passing them to the handler.
            else if (Trigger.isUpdate)
            {
                List<SObject> lstOfNewSo = new List<SObject>();
                for (SObject so : Trigger.old)
                {
                    lstOfNewSo.add(Trigger.newMap.get(so.Id));                        
                }
                beforeUpdate(Trigger.old, lstOfNewSo, Trigger.oldMap, Trigger.newMap);
            }

        } else { // After Trigger
            // Iterate through the records deleted passing them to the handler.
            if (Trigger.isDelete)
            {
                afterDelete(Trigger.old, Trigger.oldMap);
            }
            // Iterate through the records inserted passing them to the handler.
            else if (Trigger.isInsert)
            {
                afterInsert(Trigger.new, Trigger.newMap);
            }
            // Iterate through the records updated passing them to the handler.
            else if (Trigger.isUpdate)
            {
                List<SObject> lstOfNewSo = new List<SObject>();
                for (SObject so : Trigger.old)
                {
                    lstOfNewSo.add(Trigger.newMap.get(so.Id));
                }
                afterUpdate(Trigger.old, lstOfNewSo, Trigger.oldMap, Trigger.newMap);
            }
    
        }
    }
    //############################### After operations ###############################
    /*
     * This method is called iteratively for each record inserted during an AFTER trigger.
     */
    
    //@TestVisible
    abstract void afterInsert(List<SObject> lstOfNewSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record updated during an AFTER trigger.
     */
    
    
    abstract void afterUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record deleted during an AFTER trigger.
     */
    
    
    abstract void afterDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo);
    //############################### Before operations ###############################
    /*
     * This method is called iteratively for each record inserted during an BEFORE trigger.
     */
    
    
    abstract void beforeInsert(List<SObject> lstOfNewSo);
    /*
     * This method is called iteratively for each record updated during an BEFORE trigger.
     */
    
    
    abstract void beforeUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record deleted during an BEFORE trigger.
     */
    
    
    abstract void beforeDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo);
}

3. TriggerFactory
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This is a factoy class of all triggers, existes in this ORG. This factory is responsible for
 *               creating factory of trigger handler class.
 */
public with sharing class TriggerFactory{
    /*
     * This method return instance of TriggerHandler.
     * Arguments:   String className - Name of handler class in string format.
     * Return triggerHandler : Instance of trigger handler class.
     *  
     */
    public static TriggerHandler getHandlerInstance(String className){
        TriggerHandler handler = getHandler(className);
        // Make sure we have a handler registered, new handlers must be registered in the getHandler method.
        if (handler == null){
            throw new TriggerHandlerException('No Trigger Handler registered of name : ' + className);
        }        
        return handler;
    }
    
    /*
     * private static method to get the appropriate handler for the object type.
     * Modify this method to add any additional handlers.
     * Arguments:   String className - Name of handler class in string format.
     * Returns:     A trigger handler if one exists or null.
     */
    private static TriggerHandler getHandler(String className){
        if (className != null && className.trim().length() > 0){
            Type t = Type.forName(className);
            return (TriggerHandler) t.newInstance();
        }        
        return null;
    }
}

4. TriggerWorker
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This is the first entry point for each trigger.
 *.
 */
global with sharing class TriggerWorker{
    /*
     * This static method is responsible to execute trigger logic with help of handler class.
     * Arguments:   String className - Name of handler class in string format.
     *  
     */
    global static void executeTrigger(String className){
        TriggerHandler handler = TriggerFactory.getHandlerInstance(className);
        handler.doExecute();
    }
}


5. AccountTriggerHandler  (ConcreteTriggerHandler class)
/**
* Trigger Handler class for Expense Detail Objcet.
*
**/
public class AccountTriggerHandler extends TriggerHandler{
    // ########### Start of defining abstract methods of Trigger Handler abstract class ###########
    public void afterInsert(List<SObject> lstOfNewSo, map<id,SObject> mapOfNewSo){
        sampleMethod(lstOfNewSo);
    }
    
    public void afterUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo){
        
    }
    
    public void afterDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo){
        
    }
    
    public void beforeInsert(List<SObject> lstOfNewSo){
        
    }
    
    public void beforeUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo){
        
    }
    
    public void beforeDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo){
        
    }
    // ########### End of defining abstract methods of Trigger Handler abstract class ###########
    
    /* here create private method(s) to perform your operation and call that method(s) 
     * from above template method based on the scenario. Suppose we need perform an 
     * operation after a record insertion, so create a private method say sampleMethod() and 
     * call it from above afterInsert() method. */

   private void sampleMethod(lstOfNewSo){
        //Perform your logic.
   }
       
}

6. AccountTrigger

trigger AccountTrigger on Account(after insert, after update, after delete, before insert, before update, before delete) {
   // Method parameter as concrete trigger handler class name.
   TriggerWorker.executeTrigger('AccountTriggerHandler');
}

LWC to LWC Communication using Lightning Messaging Service (Part - 2)

In my previous post ( previous post link ) we have learn how to create a Lightning Messaging Service with 6 steps and today we will use the ...