5

I've been researching some best practices and trigger frameworks, and I found Kevin O'Haras TriggerHandler Framework. Now I don't fully understand it, I don't understand how to reference the Trigger handler to my actual trigger, I know I'm suppose to put extend but how does everything else "handle" my trigger...? The following is a simple trigger to auto populate a field, so for future reference and knowledge how should I have gone about building this trigger using Kevin's framework?

Questions from Kevins Git -- Not sure what these are saying..

  1. In your trigger handler, to add logic to any of the trigger contexts, you only need to override them in your trigger handler.

  2. To use the trigger handler, you only need to construct an instance of your trigger handler within the trigger handler itself and call the run() method.

I'm not asking anyone to actually implement it, I'm just trying to better understand how to do it, and I think by using an example I wrote would help me.

trigger updateSamplingTransZone on Sampling__c(before insert, before update)
{
    Set<String> validCSet = new set<String>();

    if(Trigger.IsInsert || Trigger.isUpdate)
    {
        for(Sampling__c s: Trigger.new)
        {
            if (s.Country__c != null || s.Country__c != '')  
            {
                validCSet.add(s.Country__c);
                system.debug('This is ValidCSet  ' + validCSet + '\n');
            }      
        }

        List<Validation_Region__c> validationRegionList = [Select Id, Transportation_Zone__c, Country_Key__c from Validation_Region__c where Country_Key__c IN: validCSet];
        Map<String, Validation_Region__c> validationRegionMap = new Map <String, Validation_Region__c>(); 

        for (Validation_Region__c vr: validationRegionList)
        {
            validationRegionMap.put(vr.Country_Key__c, vr);
        }

        system.debug('This is validationRegionMap: ' + validationRegionMap);

        for (Sampling__c s: Trigger.new)
        {      
            if(s.SAP_Transportation_Zone__c != null || s.SAP_Transportation_Zone__c != '')  
            {
                s.SAP_Transportation_Zone__c = null;
            }
            if (s.Override__c == 'Yes')
            {
                try{
                    s.SAP_Transportation_Zone__c = validationRegionMap.get(s.Country__c).Transportation_Zone__c;
                }catch(System.NullPointerException e){
                    system.debug('Override SAP Address with Drop-Ship Info has been flagged "Yes".  The country needs to be populated in this case.');
                }
            }
        }
    }
}
  • 1
    I recommend you take a look at the following references. The first is the Tidy Trigger Pattern by Tony Scott[developer.force.com/cookbook/recipe/… ] the other is Hari Krishan's Blog [krishhari.wordpress.com/2013/07/22/… ] with his approach to a trigger implimentation that's executed via classes. In essence, the trigger fires and calls an instance of a class to run the code. – crmprogdev Apr 18 '14 at 17:05
  • That just substitutes one confusing approach with another for me. – EricSSH Apr 18 '14 at 17:12
  • Very useful links! The second link in the first comment has a "]" on the end. The link should be krishhari.wordpress.com/2013/07/22/… – Jagular Apr 18 '14 at 17:14
  • In as simple language as I can, your trigger fires on the sObject, instead of doing anything at all, it immediately calls an "instance" of a class to do everything. The "instance" only exists for the duration of the execution context of your trigger. Several other classes are used to "build up" the class you actually call at run time. Dan Appleman's Book Advanced Apex Programming also covers this concept/material. – crmprogdev Apr 18 '14 at 19:16
  • @EricSSH -- I wholeheartedly agree with @crmprogdev; I use the Tidy Trigger Pattern on every project. – cropredy Apr 18 '14 at 19:33
5

I think this is how it would be implemented. I haven't used this trigger framework myself (since I'm developing my own), but I'll give it a shot based on what I can tell in the documentation.

So, in your trigger, it will have the following:

trigger updateSamplingTransZone on Sampling__c(before insert, before update)
{
    new SamplingTriggerHandler().run();
}

You will then create you SamplingTriggerHandler. I'll use your example code to try and give the basic idea. It would look something like this (from my understanding of the documentation anyway :P).

public class SamplingTriggerHandler extends TriggerHandler 
{
  public override void beforeUpdate() { UpdateSamplingTransZone(); }
  public override void beforeInsert() { UpdateSamplingTransZone(); }

  private void UpdateSamplingTransZone()
  {
    Map<String, List<Sampling__c>> validCountryToSampleMap = 
        new Map<String, List<Sampling__c>>();

    for(Sampling__c singleSample : (List<Sampling__c>)Trigger.New)
    {
        if(String.isNotEmpty(singleSample.SAP_Transportation_Zone__c))
            singleSample.SAP_Transportation_Zone__c = null;

        if(String.isNotEmpty(singleSample.Country__c) && singleSample.Override__c == 'Yes')
        {
            if(!validCountryToSampleMap.conatinsKey(singleSample.Country__c))
                validCountryToSampleMap.put(singleSample.Country__c, 
                    new List<Sampling__c>());
            validCountryToSampleMap.get(singleSample.Country__c).add(singleSample);
        }
    }

    List <Validation_Region__c> regionValidationList = 
        [SELECT Id, Transportation_Zone__c, Country_Key__c 
         FROM Validation_Region__c 
         WHERE Country_Key__c IN :validCountryToSampleMap.keySet()];

    Map <String, Validation_Region__c> regionValidationMap = 
        new Map <String, Validation_Region__c>();

    for(Validation_Region__c validRegion: regionValidationList)
        regionValidationMap.put(validRegion.Country_Key__c, validRegion);

    for(String countryInMap : regionValidationMap.keySet())
        if(validCountryToSampleMap.conatinsKey(countryInMap))
        {
            for(Sampling__c singleSample : validCountryToSampleMap.get(countryInMap))
                singleSample.SAP_Transportation_Zone__c =
                    regionValidationMap.get(countryInMap).Transportation_Zone__c;
        }
  }
}
  • 4
    One thing that isn't always obvious is that Trigger.New is a static variable - so although you often see it being passed around from a trigger to a handling class, it is actually available when you invoke the handling class without it being passed in - which is why you can just invoke the handling class, and it knows which data to use... – BritishBoyinDC Oct 29 '14 at 20:12
  • I found that rather surprising actually. It's very good to know for later on. – Programmable Medley Oct 29 '14 at 20:14
  • @ErisSSH No problem. Glad to help. Any day with Apex is a good day for me. – Programmable Medley Oct 29 '14 at 20:15
  • @EricSSH - to further blow your mind, consider the frameworks and patterns in Enterprise Patterns by SFSE contributor Andrew Fawcett: andyinthecloud.com/2014/08/26/… . In addition to a trigger pattern, you'll be exposed to unit of work pattern, selector pattern, domain layers, service layers and the like. If you're planning on building a robust solution that will live on, well worth understanding – cropredy Oct 30 '14 at 21:13
  • Yeah, I've read up on that one. It is quite amazing. He has a book that goes over how to develop enterprise solutions using everything you mentioned above. I imagine it is well worth the purchase if he's involved. – Programmable Medley Oct 30 '14 at 21:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.