Pass multiple, strongly typed variables from Process Builder & Flow to Apex (and maybe replace some triggers while you’re at it)

Triggers. They’re fast, they’re easy, and if you follow a framework, you can have a lot of control over how they fire. But they can also be a nightmare. If something’s really, really broken, you can get yourself in a situation where you can’t make changes to your Triggers in production quickly. Even if you can, versioning still requires a deployment from your source control (assuming you have one). In those cases, wouldn’t a deployable, point-and-click tool that natively keeps its past 50 iterations for instant roll-back be better? It would. And so, to the rescue comes Process Builder!

If you are handling “after” logic for inserts or updates, it is possible to bypass triggers entirely, and set up a relationship between a Process or Flow and the Apex handler class. “But wait!”, says the reader, “when I use Process Builder, all I can send is an array of a wrapper class objects. How could I use that send get records to their handlers?” To that reader I say: Welcome to Invocable Variables!

Most readers will know it’s a good idea not to handle logic in triggers. Instead, review the nature of the change and the Trigger Context, then hand records off to appropriate Apex methods for more complex duties. For “after” logic on inserts or updates, the exact same handoff can be duplicated from a Process (or Flow) to a class in an optimally bulkified manner because you can send whatever you want to an invocable method in an Apex class so long as you define a wrapper class that contains those variables. You may just want to send Apex a variable to be used in an API request or something. But, if you want, you can even use those variables to reconstitute an array of the sObject that kicked off the process (thereby mimicking the handoff from Trigger to handler class).

This works whether you call Apex from Process Builder, or first call a Flow from Process Builder then call Apex from the Flow.

Let me demonstrate. The example below would eliminate the need for “after” handling in a trigger for some Accounts and Opportunities by:

  1. Using a process to call Apex to handoff newly created Accounts.
  2. Use that same Process to call Flow.
  3. The flow makes Opportunities related to the Accounts that kicked off the process.
  4. The flow will then send those Opportunities to Apex.
  • Start with a Process than handles events on Accounts:

  • Add criteria diamonds. Since Summer 16, you’ve been able to execute actions on more than one criteria. By doing so, you can call multiple Invocable Methods in your Apex classes depending on what’s happened to your record(s) (important note: only one invocable method is allowed per class. If you’re going to send parameters to multiple methods, you’ll need multiple classes). Handling these evaluation in criteria diamonds can take the place of evaluative logic that used to be coded in Apex. For our demo, we’ll restrict the first diamond only to execute actions on Account inserts by setting its evaluative formula to ISNEW(). We won’t specify any criteria for the 2nd diamond (we’ll be handling its handoff criteria in Flow designer):
  • Now we need to specify some actions. Each diamond will have one action. For the first criteria diamond’s action, let’s call Apex directly from Process Builder. To do so, we need to have a class with an invocable method. If we’ve not specified any parameters for our invocable method, we won’t see an option to send parameters in Process Builder:

  • So, let’s create a class that looks like this.
  • Now, we have the option to set the variables of an AccountParameter wrapper class object for each Account being created:

  • Our next criteria diamond sends Accounts to this simple flow:

  • The flow starts by receiving data from Process Builder to set its variables:

  • Use the AccountId and AccountName variables sent to the flow to create an Opportunity (where {!OppName} is a simple formula {!AccountName} + ' Opp':

  • The flow then inserts the Opps and sends them to this invocable method:

  • So, running the following anonymous Apex to insert two Accounts:

insert new Account[]{new Account(Name='Test Account 1'),new Account(Name='Test Account 2')};

…brings back these debug statements:

****** accounts: (Account:{Id=001i0000027njZKAAY, Name=Test Account 1}, Account:{Id=001i0000027njZLAAY, Name=Test Account 2})
****** opps: (Opportunity:{Id=006i000000iDWy9AAG, Name=Test Account 1 Opp, Amount=1.0, CloseDate=2017-02-24 00:00:00}, Opportunity:{Id=006i000000iDWyAAAW, Name=Test Account 2 Opp, Amount=1.0, CloseDate=2017-02-24 00:00:00})

And there we go! Without using a trigger, we were able to:

  1. Insert Accounts
  2. Send them to a Apex handler method
  3. Launch a flow and create Opportunities for those Accounts
  4. Send the Opportunities to their own Apex handler method

Obviously, there are plenty of situations where triggers are required, but hopefully this illuminates at least a couple instances where clicks can replace code.

Posted in Learning