Friday, March 7, 2014

Continued... Salesforce URL Hacking to Prepopulate Fields on a Standard Page Layout using Tooling API

Here are the pros and cons using Tooling API in force.com development purpose. In my earlier post here to get the CustomField Ids and auto populate some of the CustomObject field values on Standard layout I used Tooling API to get it done. But......

Cons:

1. This process won't work other Salesforce users apart from Admins or equivalent privileged users only. This is no where documented, but this API meant for external languages to build tools for force.com, in this way some what very clear that we should be careful while using these type of APIs.

2. Only work with CustomFields on CustomObjects

Pros:

1. Not required to store the static CustomField Ids in a CustomSettings or CustomObject.

2. Not required to hack the URL with static CustomField Ids.


So I did a work around as inserting the Tooling API information in a CustomObject so that I can use this CustomObject to fetch the fieldIds and auto populate the values for the same for Salesforce users who are not admins.


Happy coding.....





Tuesday, March 4, 2014

Salesforce URL Hacking to Prepopulate Fields on a Standard Page Layout using Tooling API

To build Salesforce URL’s to standard pages for creating records, that can be applied to Custom Buttons in order to pre-populate field values when a user clicks a button native using Tooling API.

Tooling API support for Custom Object and Custom Fields

This can query (REST or SOAP) the CustomObject and CustomField objects (which are not accessible via Apex SOQL).As we know every object in Salesforce has an ID and thia API has the means to obtain the custom field Id’s.

We have  Apex wrapper for the Tooling API which can referred here

I tried to use the REST and getting a CustomObject's CustomFields Ids by using the below approach..

This code is just my work according to my requirement and can be extended up to your requirements..

NOTE: This supports only for CustomObjects and CustomFields.

To test this send the object name to the below method.

FieldIdUtil.findFieldIds('CustomObjectName') //Don't Append '"__c" for example
FieldIdUtil.findFieldIds('Implementation') //Don't Append '"__c"
You should give the object name but not the API name

This method will return map of custom fields with the respective field IDs from which we can grab the fields what ever we want to pre-populate

1. Consider the objectname is 'Implementation' and the fields in this are  'Field1', 'Field2';



1:  public class FieldIdUtil   
2:  {  
3:       public Static Map<String,String> fieldIdsMap = new Map<String,String>();  
4:       public Static String objectId; 
         
         public static List CustomApexTypes = new List();
 
 public class CustomApexType
        {
           public String Id;
           public String DeveloperName;
        }

5:       public static Map<String,String> findFieldIds(String ObjectName)   
6:    {  
7:         String objectIdQuery = 'Select Id From CustomObject Where DeveloperName = \''+ObjectName+'\'';  
8:      sendCallout(objectIdQuery, true);  
9:      if(objectId != null)  
10:      {  
11:        String fieldIdsQuery = 'Select Id, DeveloperName From CustomField Where TableEnumOrId = \''+objectId+'\'';  
12:        sendCallout(fieldIdsQuery, false);  
13:      }  
14:         return fieldIdsMap;  
15:       }  
16:       private static void sendCallout(String query, boolean flag)  
17:       {  
18:            String strIdValue,devName;  
19:            HttpRequest req = new HttpRequest();  
20:      req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());  
21:      req.setHeader('Content-Type', 'application/json');  
22:      String environmentURL =   
23:          URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v28.0/tooling/query/?q=' + EncodingUtil.urlEncode(query, 'UTF-8');  
24:      req.setEndpoint(environmentURL);  
25:      req.setMethod('GET');  
26:      Http h = new Http();  
27:      HttpResponse res = h.send(req);  
28:      JSONParser parser = JSON.createParser(res.getBody());  
29:      while (parser.nextToken() != null)
  {
      if ((parser.getText() == 'records'))
      {
          parser.nextToken();
  
          CustomApexTypes = (List<CustomApexType>)parser.readValueAs(List<CustomApexType>.class);
      }
  }  
64:   }  
65:  }  

The below code will generate the URL and the parameters from the above methods and do the redirect to a standard page by auto populate the specified values


1:  public PageReference doredirect()  
2:    {  
3:         Map<String,String> fieldIdsMap = new Map<String,String>();  
4:          Set<String> fieldAPINames = new Set<String>  
5:        {'Field1','Field2'};  
8:         fieldIdsMap = FieldIdUtil.findFieldIds('Implementation');//Passing the custom object name  
9:         PageReference pr = new PageReference(URL.getSalesforceBaseUrl().toExternalForm() + '/' + Implementation__c.SObjectType.getDescribe().getKeyPrefix() + '/e');  
10:         Map<String, String> params = pr.getParameters();  
           //we will be able to get the Master or Lookup id like this '00N11000000GysA' but inorder to refer in page we should add "CF"
            to the ID"
11:         //params.put('CF00N11000000GysA', Opp.Name);  // if you have parent object like opportunity we need to do this bit
12:      //params.put('CF00N11000000GysA' + '_lkid', Opp.Id);  // if you have parent object like opportunity we need to do this bit

13:         for(String fieldAPIName : fieldAPINames)  
14:         {  
15:           params.put(fieldIdsMap.get(fieldAPIName), (String) Opp.get(fieldAPIName));  
16:            }  
17:         params.put('saveURL',opp.id);  
18:      params.put('retURL', opp.id);  
19:         pr.setRedirect(true);   
20:         system.debug('*************' + pr);  
21:         return pr;  
22:    }  

This is just my initial thoughts and worked solution for me ..There may be some changes and best practices you may found to change in this code....

here is my experience in making this solution before taking to Production.