When Salesforce is life!

Tag: Apex Page 2 of 3

[Salesforce] The Sobject Crusade: ApexTestResult

Source: ApexTestResult

After you execute a test class (ApexTestQueueItem), you’ll get the test results of a given test method execution.

To query this information use the ApexTestResult object.

The object conveys the following fields:

  • ApexClassId: the test class
  • ApexLogId: the ApexLog object (if log is enabled)
  • AsyncApexJobId: the main aync job (this is the same as ApexTestQueueItem.ParentJobId) to which the given test execution belongs
  • Message: the exception message, only if an exception occurs
  • MethodName: the test method name of the given log
  • Outcome: the result of the test method execution (Fail, Pass, CompileFail)
  • QueueItemId: lookup to the ApexTestQueueItem the result belogs to
  • StackTrace: exception stack trace (if any)
  • TestTimestamp: test execution date/time

To launch a test, see the instructions on the ApexTestQueueItem object page.

Now you can query for the results:

Select Id, ApexClass.Name, MethodName, ApexLogId, Outcome, TestTimestamp, AsyncApexJobId, QueueItemId From ApexTestResult order by TestTimestamp DESC

Given this failing test class:

@isTest
private class ExceptionTestClass {
    
    private static testmethod void failMethod(){
     update new Case(Subject = 'Test');
    }
}

The execution will lead to a test error:

[Salesforce] The Sobject Crusade: ApexTestSuite

Source: ApexTestSuite

String ’16 comes with a handy feature regarding test execution, the Test Suites.

They are a collection of tests ment to be run together organized in a single suite.

To access the test suite open your Developer Console and click Test > New Suite and enter the Suite name:

Then select all test classes you want to run in the suite:

In the Test > Suite Manager menu item you can change a suite’s configuration, while in Test > New Suite Run you can choose which suites to execute.

The Settings button allows to set the maximum number of failuers allowd, so the test suite ends its run immediately after a given number of exceptions are thrown.

Clicking Run the tests are executed and presented on the Tests tab on the lower side of the Developer console:

You can query the Object easily.

Select Id, TestSuiteName From ApexTestSuite

To check for the classes involved in the suite you need to query the TestSuiteMembership that links Apex classes to the Suite, but it is another story.

[Salesforce] The Sobject Crusade: ApexClass

Source: ApexClass

The ApexClass is the most beloved object for Salesforce Developers.

It identifies a specific Apex Class, so you can query for Classes runtime.

Note that, even if the describe states that the ApexClass is creatable and updatable, an exception is thrown if you try to insert/update via API a class: use the tooling API or metadata API instead.

Among the fields, you can query for the Body of the class, whether it is valid or not, size in byte without comments.

Here an example:

Select Id, Name, ApiVersion, Body, IsValid, LengthWithoutComments From ApexClass ORDER BY Name

[Salesforce / Lightning Connect] Lightning Connect Custom Adapters and MongoDB (DML support) pt.2

Do you remember the Lightning Connect Custom Adapters and MongoDB post?

Things have changed after that post and finally the platform supports all DML statements: insert, update and delete!

To make the magic work I had to make:

Follow the post instructions to setup up your Heroku app.

The core changes are the support for the methods.

Open the MongoDBDataSrouceProvider.cls class:

override global List getCapabilities() {
 List capabilities = new List();
 capabilities.add(DataSource.Capability.ROW_QUERY);
 capabilities.add(DataSource.Capability.SEARCH);
 //new capabilities added
 capabilities.add(DataSource.Capability.ROW_CREATE);
 capabilities.add(DataSource.Capability.ROW_UPDATE);
 capabilities.add(DataSource.Capability.ROW_DELETE);

 return capabilities;
}

The provider has been added with more capabilities, CREATE, UPDATE and DELETE.

Let’s open the MongoDBDataSourceConnectio.cls class and look at the 2 new methods:

global override List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext context) {
    List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>();
    List<Map<String, Object>> rows = context.rows;
    Http h = new Http();
    
    for(Integer i = 0; i < rows.size(); i++){
        Map<String,Object> row = rows[i];
        HttpRequest request = new HttpRequest();
        request.setHeader('Content-Type','application/json');
        request.setTimeout(60000);
        Map<String,Object> invoice = new Map<String,Object>();
        if(String.isBlank((String)row.get('ExternalId'))){
            request.setMethod('POST');
            request.setEndpoint(DB_ENDPOINT_NC);
        }else{
            request.setMethod('PUT');
            request.setEndpoint(DB_ENDPOINT_NC+'/'+row.get('ExternalId'));
        }
        
        invoice.put('accountid', row.get('Account'));
        invoice.put('contractid', row.get('Contract'));
        invoice.put('created', row.get('CreatedDate'));
        invoice.put('amount', row.get('Amount'));
        invoice.put('description', row.get('Description'));
        
        request.setBody(JSON.serialize(invoice));
        
        HttpResponse response = h.send(request);
        
        List<Object> mList = (List<Object>)JSON.deserializeUntyped(response.getBody());
        Map<String, Object> m = (Map<String, Object>)mList[0];
        if (response.getStatusCode() == 200){
            String objId = String.valueOf(m.get('_id'));
            if(String.isBlank(objId)){
                objId = String.valueOf(row.get('ExternalId'));
            }
            results.add(DataSource.UpsertResult.success(objId));
        } 
        else {
            results.add(DataSource.UpsertResult.failure(
                String.valueOf(row.get('ExternalId')), 'The callout resulted in an error: ' + response.getStatusCode()+' - '+response.getBody()));
        }
    }
    return results;
}

global override List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext context) {
    List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>();
    Http h = new Http();
    
    for (String externalId : context.externalIds){
        HttpRequest request = new HttpRequest();
        request.setHeader('Content-Type','application/json');
        request.setTimeout(60000);

        request.setMethod('DELETE');
        request.setEndpoint(DB_ENDPOINT_NC+'/'+externalId);
        
        HttpResponse response = h.send(request);
        if (response.getStatusCode() == 200
            || response.getStatusCode() == 201){
            results.add(DataSource.DeleteResult.success(String.valueOf(externalId)));
        } 
        else {
            results.add(DataSource.DeleteResult.failure(
                String.valueOf(externalId), 'The callout resulted in an error: ' + response.getStatusCode()+' - '+response.getBody()));
        }
    }
   return results;
}

WARNING: this code is not optimized for bulk upsert/delete because it makes a callout for every record.

It’s a proove of concept, so I challenge you to bulkify the class!

How can you insert an external object provided by a Lightning Connect adapter?

The Database class has been provided with new methods:

  • deleteAsync
  • insertAsync
  • updateAsync

These methods are used to make the calls to the remote system and actually do the work!

Database.insertAsync(new List<MongoDB_Invoice__x>{
    new MongoDB_Invoice__x(Amount__c=1, Description__c ='Async Test 1'),
    new MongoDB_Invoice__x(Amount__c=2, Description__c ='Async Test 2')
});
Database.deleteAsync([Select Id From MongoDB_Invoice__x Where Description__c = 'Async Test 1']);

Every method has an alternative method that provides a callback class, which allows to make further actions after the records are upserted/deleted.

For instance, the asyncUpdate has an optional second parameter of type Database.AsyncSaveCallback that can be created to execute some logic after a specific record is done (the class is called every time a record is updated).

Every asyncDML method returns a List of Database.DeleteResult or Database.SaveResult that contains a link to the asynchrounous operation that can be retrieved by calling the Database.getAsyncLocator(result) method and passing the value to the Database.getAsyncSaveResult(asyncLocator) or Database.getAsyncDeleteResult(asyncLocator): this way you can get the status of the asynchronous operation.

[Salesforce / Apex] Let’s play with Named Credentials and OAuth 2.0

Few days ago I was lurking in the Named Credentials configurations.

What are named credentials?

Here are the official docs.

They are essentially a way to store callout configurations such as:

  • Endpoint (only HTTPs endpoints are supported)
  • Callout certificate (if needed, from the local key store)
  • Authentication protocol (if needed)
  • Authentication settings

With named credentials you don’t need Remote Site Setting configuration anymore: add you credential and the job is done!

The Endpoint stores the callout URL but it could also store a part of the endpoint (e.g. only the domain or a specific piece of path, such as https://na1.salesforce.com/services/Soap/class/).

The Callout certificate grabs a certificate from the Certificate and Key Management setup page, allowing a more secure connection between hosts.

I’m going to focus on the Authentication protocol.

You can choose among the following values:

  • No Authentication
  • Password authentication
  • OAuth 2.0

And you can set the authentication globally (Identity type = Named principal) or per user (Identity Type = Per User): if you don’t need any authentication, just use the value “Identity Type = Anonymous”

The password authentication is pretty straightforward: it uses BASIC authentication (username/password BASE64 encoded sent in the request headers).

But what about OAuth2?

I wanted to test this option using all but the Salesforce platform: there are plenty of services that expose the OAuth 2.0 authentication, but I love Salesforce and that’s how I want to test things!

You need 2 orgs:

  • Remote ORG: this will be the provider of your OAuth 2.0 authentication, it hosts the remote service you want to access (and that you can only access with this ORG’s user)
  • Local ORG: this is the ORG where you want to invoke the remote service and where you are configuring the Named Credentials

Setup the Remote ORG

First let’s setup the remote service.

Create a new SOAP webservice:

global class EchoManager {
    webservice static String echo(String text){
        return 'ECHO FROM ORG '+UserInfo.getOrganizationId()+': '+text;
    } 
}

This service echoes the request text’s returning also the remote ORG ID.

Useful uh?

Go to Setup > Develop > Apex Classes search the EchoManager class and click the WSDL link next to the class name: this way you can download the WSDL file you are going to import in the Local ORG to call the service.

Make sure the remote user you’ll be using (with OAuth2) to consume the service from the Local ORG is enabled to access the Apex Class (from its Profile or assigning a Permission set: if this is an Administrator profile no need to check!).

Last step on this org is to setup a Connected App: this confgiuration will give access to the ORG from outside on behalf of an external application.

Go to Setup > Create > Apps, scroll to the Connected Apps section and click the New button:

Setup a name, a contact Email, a logo image (I choose Master Yoda).

Flag Enable OAuth Setting and set Callback URL to a fake value (e.g. callback://myapp): we’ll be configuring this field later (this hosts the callback url of the Local ORG).

Finally set the full and refresh_token scopes (the last one is necessary to allow for sending refresh token).

Onve you save it can take 5/10 minutes for the changes to be propagated.

This is pretty much what you see now (except for the Callback URL):

Let’s go back to the Local ORG.

Setup the Local ORG

First let’s import the remote service WSDL from Setup > Develop > Apex Classes and click the Generate From WSDL button.

Select the WSDL file just saved from the Remote ORG, use a namespace name (WSEchoManager in my case) and Salesforce will create the Apex Stub.

Let’s create a Visualforce page with a controller to test it:

public class EchoController {
    public String requestText{get;set;}
    public String responseText{get;set;}
    public void sendRequest(){
        this.responseText = null;
        try{
            WSEchoManager.EchoManager stub = new WSEchoManager.EchoManager();
            this.responseText = stub.echo(this.requestText);
        }catch(Exception e){
            this.responseText = 'Unexpected exception :'+e.getMessage();
        }
    }
}

<apex:page controller="EchoController" tabStyle="Account">
    <apex:sectionHeader title="Remote echoes" />
    <apex:form>
        <apex:pageBlock>
            <apex:pageBlockSection columns="2">
                <apex:pageBlockSectionItem>
                    <apex:outputLabel>Say something:</apex:outputLabel>
                    <apex:inputText value="{!requestText}" />
                </apex:pageBlockSectionItem>
                <apex:commandButton value="Send request" action="{!sendRequest}" />
            </apex:pageBlockSection>
            <apex:pageBlockSection columns="1" 
                                   title="Server response" 
                                   rendered="{!NOT(ISBLANK(responseText))}">
                <apex:outputText value="{!responseText}" />
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Let’s try it:

As expected we haven’t still enabled anything.

Jump to Setup > Security Controls > Auth. Providers and click the New button and choose the Salesforce provider type:

This is the authentication provider will be using to initiate the OAuth 2 dance with the Remote ORG.

In the Consumer Key and Consumer Secret fields set the values from the Remote ORG connected app (called Consumer Key and Secret as well).

The Authorization Endpoint URL and Token Endpoint URL are setup with the https://login.salesforce.com/services/oauth/… values, but in this case I’ve used the Remote ORG custom domain (you can leave with the default values).

In the Default Scopes set the selected scopes in the Remote ORG connected app separated by a blank space (full refresh_token).

Now click “Save” and get the Callback URL you get in the Salesforce Configuration section:

Go back to the Remote ORG connected app and set the Callback URL with the one just copied.

We are about there, don’t worry!

Go back to your Local ORG and go to Setup > Security Controls > Named Credentials and click New.

Give a fantastic name to your named credential (you’ll be using it in your stub class), set the URL with the service url you find in the WSEchoManager class:

 . . .
    public class EchoManager {
        public String endpoint_x = 'https://eu6.salesforce.com/services/Soap/class/EchoManager';
        public Map<String,String> inputHttpHeaders_x;
    . . .

Set the Named Principal Identity Type and the OAuth 2.0 protocol; select the Authentication Provider just configured and flag the Start Authentication Flow on Save: this way, upon saving the named credential, you are requested to access to the remote provider.

Flag Allow Merge Fields in HTTP Body as well in order to put the OAuth token inside the request in a “non standard” way (we dont’ want to use the Authorication: Bearer XXX header).

Cheers: you have a working connection!

Finally we have to change the stub code to recall the named credential:

 . . .
    public class EchoManager {
        public String endpoint_x = 'callout:Echo_Service';
        . . .
        public String echo(String text) {
            WSEchoManager.echo_element request_x = new WSEchoManager.echo_element();
            request_x.text = text;
            this.SessionHeader = new SessionHeader_element();
            this.SessionHeader.sessionId = '{!$Credential.OAuthToken}';
        . . .

We are using the Echo_Service named credential in the endpoint_x member and adding the SessionHeader parameters in the SOAP request using the named credential merge field {!$Credential.OAuthToken}, which stores the token needed to authorize the call.

Thanks to the Allow Merge Fields in HTTP Body the engine replaces automagically this string with the session ID referenced by the merge field inside the SOAP request…and:

You can find the full code in the following Github repository.

[Salesforce / Custom Settings] How and Why

This is a beginner’s guide to Custom Settings, that shows a practical way of using all the features they convey.

For TL;DR people, this is the GitHub repository of the example.

One of the greatest pros of the Force.com platform is the extraordinary quick development phase: even when you are under continous software development, you can change your processes implementation within minutes.

With great features come great responsibilities, that’s why you should give administrators, who may not be developers, the same power to configure the code flow.

Before the introduction of custom settings, the only options were:

  • Hard coding constants on your classes
    • Pros: Simple to handle for developers
    • Cons: You need a deploy every time you need to change a value

  • Creating custom objects where storing your configuration (even if only 1 set of data)
    • Pros: High flessibility
    • Cons: You need to do a query every time you need a configuration value (this could be painfull in large and complex implementations)

The introduction of Custom settings made developer lifes easier.

A Custom Setting is an SObject that is available in every execution context (i.e. within apex classes, triggers, visualforce pages, formulas, workflows, …) without the need of query, so basically you always have an instance of an object with all its fields ready to be used.

Let’s do it

Let’s start with a simple Visual Force page that shows, calling a public API, a random quote, *QuoteOfTheDay.page*:

<apex:page controller="QuoteOfTheDayController" action="{!onLoad}" tabStyle="Idea">
    
    <b><apex:outputText value="{!qod}" escape="false" /></b>
     
    <i>{!author}</i>
    
    <hr />
    
    <i>Quote of the day - <b>{!dt}</b></i>
    
    <br/> 
    
    <apex:pageBlock rendered="{!DEBUG_MODE}">
        <apex:pageBlockSection  title="Callout details" columns="1">
        
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Endpoint" />
                <apex:outputPanel>{!CALLOUT_ENDPOINT}</apex:outputPanel>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Timeout" />
                <apex:outputPanel>{!CALLOUT_TIMEOUT}</apex:outputPanel>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem>
                <apex:outputLabel value="Error Message" />
                <apex:outputPanel>{!errorMessage}</apex:outputPanel>
            </apex:pageBlockSectionItem>
            
        </apex:pageBlockSection>
        
    </apex:pageBlock>
    
</apex:page>

public with sharing class QuoteOfTheDayController {
    
    public String CALLOUT_ENDPOINT{
        get{
            return ConfigurationManager.CALLOUT_ENDPOINT;
        }
    }
    
    public Integer CALLOUT_TIMEOUT{
        get{
            return ConfigurationManager.CALLOUT_TIMEOUT;
        }
    }
    
    public Boolean DEBUG_MODE{
        get{
            return ConfigurationManager.DEBUG_MODE;
        }
    }
    
    public String DATE_FORMAT{
        get{
            return ConfigurationManager.getDateFormat(UserInfo.getLocale());
        }
    }
    
    //quote of the day
    public String qod{get;Set;}
    //quote of the day author
    public String author{get;Set;}
    //date of request
    public String dt{get;set;}
    //debug message
    public String errorMessage{get;Set;}
    
    //loads the Quote of the Day on load
    public void onLoad(){
        
        //date of callout
        DateTime dateOfCall = System.now();
        
        try{
            Http h = new Http();
            HttpRequest request = new HttpRequest();
            request.setEndpoint(CALLOUT_ENDPOINT);
            request.setTimeout(CALLOUT_TIMEOUT);
            request.setMethod('GET');
            HttpResponse response = h.send(request);
            List<String> result = getQuoteFromResponse(response);
            this.qod = result[0];
            this.author = result[1];
        }catch(Exception e){
            this.qod = 'Something bad happened. Please reload';
            this.errorMessage = e.getMessage();
        }
        this.dt = dateOfCall.format(DATE_FORMAT);
    }
    
    /*
    Parse the "Quote Of The Day" API response (details @ http://quotesondesign.com/api-v4-0/)
    @return - List<String> contains 0 => quote, 1 => author 
    */
    public static List<String> getQuoteFromResponse(HttpResponse response){
        String resp = response.getBody();
        List<Object> jsonResponse = (List<Object>)JSON.deserializeUntyped(resp);
        Map<String,Object> quote = (Map<String,Object>)jsonResponse[0];
        String quoteString = (String)quote.get('content');
        String authorString = (String)quote.get('title');
        return new List<String>{quoteString, authorString};
    }
    
    public class CustomException extends Exception{}
}

On page load, the controller:

  1. Stores date/time of request
  2. Creates an HttpRequest setting its endpoint, timeout, method (GET)
  3. Sends the request and parses the response (getting the quote and the author)
  4. Formats the callout’s date depending of current User’s locale

The DEBUG_MODE allow to see some info about the current callout (for debug porpouses).

On the page controller we have no configuration, because they are written on the following utility class:

public class ConfigurationManager{
    
    //global endpoint
    public static String CALLOUT_ENDPOINT{
        get{
            return 'http://quotesondesign.com/wp-json/posts?filter[orderby]=rand';
        }
    }

    //global timeout in ms
    public static Integer CALLOUT_TIMEOUT{
        get{
            return 60000;
        }
    }

    //user/profile centric debug mode
    public static Boolean DEBUG_MODE{
        get{
            return false;
        }
    }

    //returns a specific date format given the locale code
    public static String getDateFormat(String localeCode){
        if(localeCode == 'it_IT'){
            return 'dd/MM/yyyy';
        }
        return 'MM/dd/yyyy';
    }

}

The result is:

Before running the page remember to add the http://quotesondesign.com endpoint among the trusted endpoints for the ORG, by selecting Setup > Security Controls > Remote Siste Settings.

Now let’s open the page:

You can change the hardcoded configurations on the ConfigurationManager class: let’s set the DEBUG_MODE variable to true:

This example clearly shows that it is hard, for non developers, to alter the configurations.

Here come the Custom Settings: they are Custom Objects that can be used without making any SOQL and are fitted to current User’s context.

Let’s create a new Custom Setting with Setup > Custom Settings > New:

The Hierarchic custom setting is a setting that has a global value for its fields which can be overridden on a per User / User’s Profile basis.

This will be more clear later.

A Custom Setting is just like a Custom SObject, so you can add all fields you want (with some exceptions on the types):

To set a value for the fields, click on the Manage button and then on the **Edit** button:

These are global values for the fields and they will be the only values we will be needing for this custom setting.

Set the same values we have on the ConfigurationManager class.

Let’s create another Custom Setting for the DEBUG_MODE flag:

Let’s set a global value with Manage > Edit:

Then click the New button on the lower section of the “Manage” page and add new values for the “System Administrator” profile:

This means that the Debugging custom setting will have a global value and a value fitted for System Administrator users: every administrator that will execute the page will see the debug section.

Finally let’s add the last custom setting for the date formats, by choosing a List type:

With the following fields:

This time, when creating a new value, we will have a set of values (remember the List type) instead of global/user/profile values, each one identified by a Name field:

For each locale code you can set a specific date format plus a Default value (to be handled manually).

Now that we have create all the settings, we need to link them to the code, so let’s change the *ConfigurationManager* class accordingly:

public class ConfigurationManager{
    
    //global endpoint
    public static String CALLOUT_ENDPOINT{
        get{
            return Endpoints__c.getOrgDefaults().Callout_Endpoint__c;
        }
    }

    //global timeout in ms
    public static Integer CALLOUT_TIMEOUT{
        get{
            return Endpoints__c.getOrgDefaults().Callout_Timeout__c.intValue();
        }
    }

    //user/profile centric debug mode
    public static Boolean DEBUG_MODE{
        get{
            return Debugging__c.getInstance().Callout_Debug_Mode__c;
        }
    }

    //returns a specific date format given the locale code
    public static String getDateFormat(String localeCode){
        Date_Formats__c defaultFormat = Date_Formats__c.getInstance('Default');
        Date_Formats__c localeFormat = Date_Formats__c.getInstance(localeCode);
        if(localeFormat != null) return localeFormat.Format__c;
        return defaultFormat.Format__c;
    }

}

From now on if you need to change the endpoint of the service, debug a specific user or change data format according to user locale, you will not need to change the code but you can train an administrator to do it by him self.

There is only some limitation:

In this brief article you have:

  • Created 2 different Hierarchic Custom Settings
  • Created a List Custom Setting
  • Managed all kind of values (global, profile, list)
  • Recalled their values from Apex controller
  • Been an **awesome** developer

Here are some useful resources:

  • GitHub repository of the article
  • Salesforce Docs: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_customsettings.htm?search_text=custom%20settings
  • Custom settings methods: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_custom_settings.htm?search_text=custom%20settings
  • Custom settings limits: https://help.salesforce.com/apex/HTViewHelpDoc?id=cs_limits.htm&language=en_US
  • Live example: https://blog-enreeco-community-developer-edition.eu5.force.com/examples/QuoteOfTheDay

[Salesforce / Apex Formula] Help me testing my Apex Formula Algorithm!

a{color:red !important;}

This is a call to arms!

In the past months I have developed an implementation in Apex of Salesforce Formulas in order to have a way to use a formula result dynamically without the need to have a custom field on an object.

It has been a huge work and a lot has still to be done, but I need your help to create a big testbook of formulas, in order to point out bugs, errors, and wathever is bad in this implementation.

This implementation supports (syntax guide here):

  • Base object fields (e.g. MyField__c == 4)
  • Lookup fields (e.g. Relation__r.Account.Name == ‘ACME’)
  • Constants (e.g. $PI, EE, $TODAY, $NOW, $RANDOM
  • Logical operators in function style or inline (e.g. AND(true,false) ; true && false)
  • IF and CASE flow expressions (e.g. IF(true,1,0) )
  • Various String functions (e.g. LEFT(“String”,2) )
  • Various Math functions (e.g. POW(2,5) )
  • Type conversion functions (e.g. DATE(“2015-05-23”) )
  • DateTime functions (e.g. DATETIME(2015,12,01,0,0,0) ; ADDYEARS($TODAY, 10) )
  • Multiline comments
  • Access to Hierarchy Custom Settings (e.g. $Setup.HierarchyCS__c.Value__c)
  • Access to Hierarchy Custom Settings (e.g. $Setup.ListCS__c[“aName”].Value__c)

You can set different return types:

  • BOOLEAN
  • NUMBER
  • STRING
  • DATE
  • DATETIME

For the NUMBER return type you can also set a Scale attribute.

Once released the method call will be something like:

String formula = 'IF(NumberOfEmployees > 15, NumberOfEmployees, NumberOfEmployees/2)';
String objectId = '001000000123456789AAA';
String objectType = 'Account';
String returnType = 'NUMBER';
String scale = 2;
ApexFormulaResult formulaResult = ApexFormulaParser.evaluate(formula, objectId, objectType, returnType, scale);

Here is the Apex Formula Playroom I’ve built with Salesforce Site.

I’ve create a custom object, TestObject__c, which you can select to try the algorithm, which has all kind of Salesforce fields.

This is the raw interface of the playroom:

  1. List of all custom objects you can use (if you need more tell me!). Click on the name to select it.
  2. These are the details (with the objects field API names) of the selected object
  3. You can also test custom settings as well
  4. You can select a built-in formula or you can set a specific Output Type and Scale
  5. Formula’s body and any suggestion you want to give me, and the formula result as well

Every formula you input and calculate is stored in the Site, so please avoid using personal informations that you don’t want to share!

Feel free to break down my code, I expect a lot of work in error handling, but the awesome Developer Salesforce Community< is here to help, isn’t it?

And remember:

[Salesforce / REST APIs] API Request limit on REST header response

Plyaing with Salesforce APIs for a super secret project I came across at this (the red one) response header:

{
    date : "Fri, 31 Jul 2015 22:20:47 GMT",
    set-cookie : -[
       "BrowserId=8gV_vxxxT--xxxi0bg0vug;Path=/;Domain=.salesforce.com;Expires=Tue, 29-Sep-2015 22:20:47 GMT",
    ],
    expires : "Thu, 01 Jan 1970 00:00:00 GMT",
    sforce-limit-info : "api-usage=113/5000000",
    last-modified : "Fri, 24 Jul 2015 12:07:09 GMT",
    content-type : "application/json;charset=UTF-8",
    transfer-encoding : "chunked",
}

This is basically the number of API requests done since this last call, and it can be used to train external systems not to fail when exceeding this limit.

I’m sure this has been there since the beginning of times and it may be documented and, as a Salesforce expert, I should know it, but it is worth an article!

Only thing to know is that the limit is not precise, this is recalculated asynchronously and thus the number may be not the exact current amount.

To test this try my own REST request utility and try to call a simple global describe:

     GET https://[your_instance].salesforce.com/services/data/v34.0/sobjects/
     Headers
     Authorization: Bearer [a_valid_session_id]

[Salesforce/ Lightning] inputLookup: the missing component

Or quick tips on how to implement your own inputLookup Salesforce ligthning component

This is a repost of the article I published on Salesforce Developer Blog.

Salesforce Spring ’15 release brought some brand new components ready to be used in your lightning apps. One of the missing components that could be useful for your apps is the input lookup component. The idea is to use a typeahead input field. We are going to user Bootstrap and the Twitter typeahead component.

The idea behind this implementation is that the user will type a search on the input field and the typeahead shows a list of the first 20 items for the given object and search string. On load, the component should also load the initial value of the “name” field for the given object, if an ID value is selected.

This is how the component will look:

For those of you who don’t want to read more and just use the component, jump to the inputLookup github repo.

To ensure proper script loading we will use RequireJS with the trick proposed in this blog post.

Let’s first have a look at the lookupInput component’s markup (github):

<aura:component controller="InputLookupController">
    
    <ltng:require scripts="/resource/RequireJS" afterScriptsLoaded="{!c.initTypeahead}" />
    <aura:handler name="init" value="{!this}" action="{!c.setup}"/>

    <!-- ... -->

    <!-- public attributes -->
    <aura:attribute name="type" type="String" required="true"/>
    <aura:attribute name="value" type="String" />
    <aura:attribute name="className" type="String" />
    <!-- PRIVATE ATTRS -->
    <aura:attribute name="nameValue" type="String"
                    access="PRIVATE"/>
    <aura:attribute name="isLoading" type="Boolean"
                    default="true"
                    access="PRIVATE"/>

    <div class="has-feedback">
        <input id="{!globalId+'_typeahead'}" type="text" 
               value="{!v.nameValue}" class="{!v.className}" 
               onchange="{!c.checkNullValue}" readonly="{!v.isLoading}"/> 
        <span class="glyphicon glyphicon-search form-control-feedback"></span>
    </div>
</aura:component>

It uses the “InputLookupController” Apex class (with required @RemoteActions).

The RequireJS components triggers “c:requireJSLoaded” event that actually makes the component load its bootstrapped Typeahead input field: note the absence of any custom namespace, that is replaced with the “c” default namespace (this is a Spring ’15 feature).

We also have an init method that ensures that all required parameters are set.

This component simply uses a “type” parameters (with the actual API name of the needed SObject) and a “value” parameter that stores the selected ID (or the loading ID).

At first we want to load on initialization (or when the value parameter changes) the content of the input (we want to see the “Name” of the pre-selected SObject and not its ID).

The initialization loading is done using the following “inputLookupController.js” method:

initTypeahead : function(component, event, helper){
        try{
            //first load the current value of the lookup field and then
            //creates the typeahead component
            helper.loadFirstValue(component);
        }catch(ex){
            console.log(ex);
        }
    }

This is the helper part:

loadFirstValue : function(component) {
        //this is necessary to avoid multiple initializations (same event fired again and again)
        if(this.typeaheadInitStatus[component.getGlobalId()]){ 
            return;
        }
        this.typeaheadInitStatus[component.getGlobalId()] = true;
        this.loadValue(component);

    },

    loadValue : function(component, skipTypeaheadLoading){
        this.typeaheadOldValue[component.getGlobalId()] = component.get('v.value');
        var action = component.get("c.getCurrentValue");
        var self = this;
        action.setParams({
            'type' : component.get('v.type'),
            'value' : component.get('v.value'),
        });

        action.setCallback(this, function(a) {
            if(a.error && a.error.length){
                return $A.error('Unexpected error: '+a.error[0].message);
            }
            var result = a.getReturnValue();
            component.set('v.isLoading',false);
            component.set('v.nameValue',result);
            if(!skipTypeaheadLoading) self.createTypeaheadComponent(component);
        });
        $A.enqueueAction(action);
    }

This piece of code simply calls the “InputLookupController.getCurrentValue” remote action that simply preload the selected record’s Name field (if any).

The “typeaheadInitStatus” property (see the full file code) is used to avoid multiple initialization of the component (the “createTypeaheadComponent” method is the method that is used to create the typeahead component: this must be executed only once!).

On the other side the “typeaheadOldValue” stores the current value, in order to understand if the value parameter is changed: this is extremely useful when some other part of the application changes the value parameters and so the component should refresh it’s inner value.

To achieve this simply see the “inputLookupRenderer.js” file:

rerender : function(component, helper){
        this.superRerender();
        //if value changes, triggers the loading method
        if(helper.typeaheadOldValue[component.getGlobalId()] !== component.get('v.value')){
            helper.loadValue(component,true);
        }
    }

This method is called every time the component is rerendered (e.g. when one of its parameters changes), and it constantly evaluates if the “value” parameter has changed since the last set; if this is true then we load again the component, without re-contructing it (“skipTypeaheadLoading” parameters of the loadValue function).

The typeahead is a simple porting of the Twitter Typeahead component with some changes, the most important of which is the call to the remote action that search (using SOSL) for all SObjects given the search term (“substringMatcher” function of the helper file):

// . . . 
    substringMatcher : function(component) {
        //usefull to escape chars for regexp calculation
        function escapeRegExp(str) {
          return str.replace(/[-[]/{}()*+?.^$|]/g, "$&");
        }

        return function findMatches(q, cb) {
            q = escapeRegExp(q);
            var action = component.get("c.searchSObject");
            var self = this;

            action.setParams({
                'type' : component.get('v.type'),
                'searchString' : q,
            });

            action.setCallback(this, function(a) {
                if(a.error && a.error.length){
                    return $A.error('Unexpected error: '+a.error[0].message);
                }
                var result = a.getReturnValue();

                var matches, substrRegex;

                // an array that will be populated with substring matches
                var matches = [];

                // regex used to determine if a string contains the substring `q`
                var substrRegex = new RegExp(q, 'i');
                var strs = JSON.parse(result);
                // iterate through the pool of strings and for any string that
                // contains the substring `q`, add it to the `matches` array
                $.each(strs, function(i, str) {
                    if (substrRegex.test(str.value)) {
                        // the typeahead jQuery plugin expects suggestions to a
                        // JavaScript object, refer to typeahead docs for more info
                        matches.push({ value: str.value , id: str.id});
                    }
                });
                if(!strs || !strs.length){

                    $A.run(function(){
                        component.set('v.value', null);
                    });
                }
                cb(matches);
            });
            $A.run(function(){
                $A.enqueueAction(action);
            });
        };
    }
    // . . .

This “complex” code is used to push the results from the “searchSObject” remote action to the typeahead result set picklist.

Finally you can add the component in your lightning app:

<aura:application >

    <aura:attribute name="id" type="String" default="" access="GLOBAL"/>
    <aura:attribute name="objNew" type="Contact" default="{'sobjectType':'Contact',  
                                                       'Id':null}" />

    <!-- ... -->

    <div class="well">
        <div class="panel panel-primary">
            <div class="panel-heading">Existent sobject</div>
            <div class="panel-body">
                <div class="form-horizontal" >
                    <div class="form-group">
                        <label class="col-sm-2 control-label">Contact</label>
                        <div class="col-sm-8">
                            <c:inputLookup type="Contact"  
                                         value="{!v.id}"
                                         className="form-control "/>
                        </div>
                    </div>
                    <div class="form-group has-feedback">
                        <label class="col-sm-2 control-label">Loaded contact</label>
                        <div class="col-sm-8 ">
                            <ui:inputText value="{!v.id}" 
                                          class="form-control"
                                          placeholder="Change id value"/>
                         </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="panel panel-primary">
            <div class="panel-heading">New sobject</div>
            <div class="panel-body">
                <div class="form-horizontal" >
                  <div class="form-group">
                    <label class="col-sm-2 control-label">Contact</label>
                    <div class="col-sm-8">
                      <c:inputLookup type="{!v.objNew.sobjectType}"
                                    value="{!v.objNew.Id}"  
                                    className="form-control "/>
                      </div>
                  </div>
                 <div class="form-group has-feedback">
                    <label class="col-sm-2 control-label">New contact</label>
                    <div class="col-sm-8 ">
                        <ui:inputText value="{!v.objNew.Id}" 
                                      class="form-control"
                                      placeholder="Change id value"/>
                     </div>
                  </div>
                </div>
            </div>
        </div>
    </div>

</aura:application>

We have two components, the first one ‘s value is grabbed directly from the “?id=XXXX” query string parameters, while the second one has no value on load:

Finally you can easily test that everytime you change the “value” input text, the inputLookup component loads it’s new “name” field, while if you search for a Contact on the component and select a record, the value input is set with the new value.

You brand new custom input lookup component is served!

[Salesforce / Apex] Integer vs Double math expressions

This is a quick post about some findings about how math expressions are handled by Apex engine, arisen from the developments of a personal package to reproduce Salesforce Formulas in Apex (and even more).

For those out there that are super expert on this field of programming, this post may seem simplicistic and “obvious”, but I think this could help a lot of guys out there that had the same problem!

Take this expression:

Double aValue = 1 / 5 * 5;

Since elementary school I learned that I could play with fractions, and in this particular example you simply reduce the 5 in the second member of the “/” operator with the third member after the “*” operator.

What’s the result?

It’s absolutely 1!

Wrong!

At first I thought I was the first to find an incredible bug, but after a while, thinking about how Java works, I understood the reason.

Try to execute this other statemanet:

Double aValue = 5 * 1 / 5;

What’s the result?

It is correctly 1.

The reason is how the “/” operator calculates:

  • If at least one operand is double/decimal, the operation is calculated in decimal style; that’s why 1.0/10 = 0.1 and 1.0/10*10 = 1 as expected
  • If both operands are integer numbers, the operation is done in the interger set of values, so 1 / 10 = 0 and the order of execution matters; that’s wky 1 / 10 * 10 = 0 and 10 * 1 / 10 = 1

In both cases the type of the result variable (Double aValue) does not affect the result, so aValue evaluates to “0.0” or “1.0”, that is a simple conversion from the integer result to a its double value.

Page 2 of 3

Powered by WordPress & Theme by Anders Norén