0

I am attempting to start this Apex class with Process Builder, triggered by a field change. I've never done this before and I'm unsure what invoke code needs to be added in order to accomplish this. I tried adding @InvocableMethod but I'm getting an error telling me this :

Compile Error: Unsupported parameter type String. 
Valid invocable parameters must be List types like List<T> 
where T is a supported type at line 26 column 27

It is a class which is currently being invoked with a Lightning Component button in a record.

public class UpdateContactPCRController {

    @InvocableMethod
    public static String  updateContact(String recordId){        
       
        String contactId = '';       
        
        List<Contact> contactToBeupdate = new List<Contact>();        
        
        if(String.isNotBlank(recordId)){            
            
            List<Program_Contact_Role__c> programContacList = [SELECT Id,Contact__c,Program_Name__c FROM Program_Contact_Role__c WHERE Id =:recordId AND Contact__c != null];
            contactId = programContacList[0].Contact__c;
            
            if(String.isNotBlank(contactId)){
                
                contactToBeupdate = [Select Id,Pardot_Action_Trigger__c,PCR_Register_Button_Link__c,PCR_URL_for_UI__c FROM Contact Where Id =: contactId Limit 1];                
                
                contactToBeupdate[0].Program_Contact_Role_Id__c = recordId;
            }
                        List<Program_Communication_Recipients__c> programCommunicationRecs = [Select Id,Name,
                                  Program_Communication__r.Program__r.Buyer__r.Name,Receipient__c,                
                                              From Program_Communication_Recipients__c Where 
                                                           Program_Communication__r.Program__c =: programContacList[0].Program_Name__c AND 
                                                           Receipient__c =: programContacList[0].Id];                                           
                                
                
                    contactToBeupdate[0].PCR_Welcome_Message__c = String.valueOf(programCommunicationRecs[0].Program_Communication__r.Welcome_Message__c);                                                    

        if(contactToBeupdate.size() > 0){
            update contactToBeupdate;  
        }
        
        return 'Updated Successfully';
    }
}
    //Calling  Http_Utility_Pardot class pardotCreateProspect method for the creation of Prospect record.
    String returnedResponseFromPardot = Http_Utility_Pardot.pardotCreateProspect(new Set<Id> {contactToBeupdate[0].Id});

Thank you very much for any help you can give with this. It is very appreciated.

1

String is not an allowed argument because Invocable Methods must be passed Lists. Below is taken from the Salesforce developer documentation on Invocable Methods. You will need to make your method accept a List<String> and return a List<String> or a another List type.

InvocableMethod Considerations

Implementation Notes

  • The invocable method must be static and public or global, and its class must be an outer class.
  • Only one method in a class can have the InvocableMethod annotation.
  • Other annotations can’t be used with the InvocableMethod annotation.

Inputs and Outputs

  • There can be at most one input parameter and its data type must be one of the following:
  • A list of a primitive data type or a list of lists of a primitive data type – the generic Object type is not supported.
  • A list of an sObject type or a list of lists of an sObject type.
  • A list of the generic sObject type (List) or a list of lists of the generic sObject type (List<List>).
  • A list of a user-defined type, containing variables of the supported types above or user-defined Apex types, with the InvocableVariable annotation. Create a custom global or public Apex class to implement your data type, and make sure that your class contains at least one member variable with the invocable variable annotation.

If the return type is not Null, the data type returned by the method must be one of the following:

  • A list of a primitive data type or a list of lists of a primitive data type – the generic Object type is not supported.
  • A list of an sObject type or a list of lists of an sObject type.
  • A list of the generic sObject type (List) or a list of lists of the generic sObject type (List<List>).
  • A list of a user-defined type, containing variables of the supported types above or user-defined Apex types, with the InvocableVariable annotation. Create a custom global or public Apex class to implement your data type, and make sure that your class contains at least one member variable with the invocable variable annotation.
7
  • thank you so much for this input. I'm going over it and I don't know how to convert these lists to the acceptable data types. Is that even possible ? Will all three of the lists need to be changed ? Thanks again. – Zoom_v Oct 6 '20 at 19:07
  • It sounds like I might just be better off creating a trigger which will call the class...? Would that involve too much ? Is the only thing I would need to set the recordid ? – Zoom_v Oct 6 '20 at 19:24
  • 1
    This is my opinion, but if you're already writing Apex for an invocable, you're probably best writing a trigger. You can make them very efficient compared to process builders. The reason why invocable methods need to be bulkified is that process builders are also bulkified. So I think, in your case, if you keep the Invocable Method you want the method signature to look like: public static void updateContact(List<Id> recordIds). How you handle the DML is dependent upon the process builder, because you could return List<Database.SaveResult>, the records you updated, or something else. – nbrown Oct 6 '20 at 20:39
  • 1
    Thanks @Zoom_v, if my answer helped please remember to accept it as the answer. – nbrown Oct 7 '20 at 13:21
  • 1
    I don't think there's one particular trigger to start you off with. What I would search for is "Apex Trigger framework". You'll find a number of blogs about how to best build your triggers to conform to best practices, make them traceable, and easy to test. Here is a good example: salesforcenextgen.com/apex-trigger-framework – nbrown Oct 7 '20 at 13:29
1

You have to write the invocable method as if it were called in bulk; hence the requirement that the input argument must be a collection.

That is, if Process Builder runs on batch of n records, and each executes an Action block that does an invocable call, SFDC batches these up into one actual invocable execution (per action block)

So, you basically have to bulkify this invocable method like you would a trigger, except instead of a Trigger.new collection to iterate over, you would have

@InvocableMethod
public static String[]  updateContact(Id[] pcrIds){

     List<Program_Contact_Role__c> programContacList = [SELECT Id,Contact__c,Program_Name__c 
       FROM Program_Contact_Role__c 
       WHERE Id =:pcrIds AND Contact__c != null];
     ...
     //  collect all the Contact__c in programContacList
     //  query or construct Contact objects
     //  update logic (bulkified)   
7
  • Thank you very much @cropredy. - After reading the responses I've gotten I think I am just going to attempt to get the method going w/ a trigger rather than make all of these changes. Is there an easy trigger which could be used to simply start the class, using an IF to only start it with a specific field change ? And to set recordid ? – Zoom_v Oct 7 '20 at 13:18
  • I tried implementing this and apparently the callout which executed at this line : contactToBeupdate[0].PCR_Welcome_Message__c = String... but I need the class to be invoked by a field change. Would I be able to accomplish this instead with a trigger which would execute BeforeUpdate ? If so, what would a trigger which would invoke upon a field change look like in this case ? – Zoom_v Oct 13 '20 at 16:35
  • Process Builder can detect field changes - use PRIORVALUE and ISCHANGED functions – cropredy Oct 13 '20 at 22:09
  • The problem isn't recognizing the changes. I believe the problem is happening because the updates are happening before the callout. This explains it : help.salesforce.com/… ; So somehow I think I need to use a BeforeUpdate trigger in order to invoke the class...? – Zoom_v Oct 14 '20 at 0:00
  • you didn't say in OP that you are doing a callout from the invocable. Please use edit to elaborate – cropredy Oct 14 '20 at 0:08

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.