Showing posts with label Random Information. Show all posts
Showing posts with label Random Information. Show all posts

06 April 2015

Skip Logic using Custom Permission

On my blog post last June, we discuss about using custom settings for skipping execution of triggers, validation rules and workflow rules. Today we can achieve the same logic using a feature Salesforce.com release last Summer 14.

But first, what is custom permission? Custom Permission allows us to extend a profile and custom permission access by allowing us to create our own "permission" attribute and can be optionally associated with a connected app. It's a simple yet powerful feature that can be use on a custom or generic application.

Below I created 3 custom permissions via Setup --> Develop --> Custom Permission.


Checking custom permission assignment in Apex Trigger requires querying the data from three setup objects called SetupEntityAccess, CustomPermission and PermissionSetAssignment. I have created a utility class that can be used to check if a user is assigned to any of the above custom permissions as below. The class cache the assignment in a permission set Id/DeveloperName and Boolean key/value pair where passing an Id or the custom permission developer name can return TRUE (if its assigned) or FALSE (if not assigned).



public class CustomPermissionUtil {
    private static Map<String,Boolean> permissionMap;
    
    public static Boolean hasCustomPermAccess(String devName){
        Boolean hasCustomPerm = false;
        if(permissionMap==null){
            refreshCache();
        }
        
        if(permissionMap.size()>0){
            if(permissionMap.containsKey(devName)){
                hasCustomPerm = permissionMap.get(devName);
            }
        }
        
        return hasCustomPerm;
    }
    
    public static Boolean hasCustomPermAccess(Id permId){
        Boolean hasCustomPerm = false;
        if(permissionMap==null){
            refreshCache();
        }
        
        if(permissionMap.size()>0){
            if(permissionMap.containsKey(permId)){
                hasCustomPerm = permissionMap.get(permId);
            }
        }
        
        return hasCustomPerm;
    }
    
    private static void refreshCache(){
        permissionMap = new Map<String,Boolean>();
        
        Set<Id> permissionIds = new Set<Id>();
        
        Map<Id,CustomPermission> customPermMap = new Map<Id,CustomPermission>(
                [SELECT Id, DeveloperName FROM CustomPermission 
                WHERE NamespacePrefix = null]);
        for(CustomPermission permObj : customPermMap.values()) {
            permissionMap.put(permObj.DeveloperName, false);
            permissionMap.put(permObj.Id, false);
            permissionIds.add(permObj.Id);
        }
        
        for(SetupEntityAccess setupEntObj : [SELECT SetupEntityId FROM 
                               SetupEntityAccess WHERE SetupEntityId in 
                               :permissionIds AND ParentID IN (SELECT 
                               PermissionSetId FROM PermissionSetAssignment 
                               WHERE AssigneeID = :UserInfo.getUserId())]){
                                                    
            permissionMap.put(setupEntObj.SetupEntityId, true);
            permissionMap.put(customPermMap.get(setupEntObj.SetupEntityId).
                DeveloperName,true);
        }
    }
    
}

To use in a trigger, an IF-condition must be added on top of the trigger code as below.

trigger TestAccountTrigger on Account (before update) {
    
    if(!CustomPermissionUtil.hasCustomPermAccess('Skip_Trigger')){
    // body of trigger
    }
    
}

For validation rule and workflow rules, a $Permission global variable is available for use.



So which one is better to use for our use-case? Custom Settings or Custom Permission? Below are the pros and cons.

Custom Settings 
Pro:
  • No SOQL required to retrieve the information (when using the custom settings method).
  • Custom Label global variable for formula.
Cons:
  • Bounded by Custom Setting data limit.
  • Access is managed on the custom setting section.
  • Data needs to be created on test classes.
Custom Permission 
Pro:
  • Custom Permission global variable for formula.
  • Assignment is aligned with how permission is given via Profile or Permission Set.
Cons:
  • Requires SOQL query to retrieve assignment.
Personally, I would go and use custom permission rather than custom settings not just because its a new feature but because it aligns to how we manage permissions to user. I would like to think that future enhancements would be released for the feature as well. However, I would recommend my readers to vote to this idea so that custom permission can be access as a global variable in Apex Code the same way we access Custom Labels. 

Happy coding!




19 December 2014

Your runAllTests request is using too many DB resources

A couple of months ago, I have encounter a very strange error when deploying components in Production where Salesforce is throwing an error message saying "Your runAllTests request is using too many DB resources". Digging deeper on the error message, I came upon this knowledge article that mentions of a limit 350,000 of DML rows on all test classes. What's fascinating is that the limit is not in the documentation. From what I understood, the limit is associated with the oracle database rollback used in the backend.

This is really a big issue specially if there are a lot of applications on your instance and you plan to add one. Also, regardless whether you optimise your code to limit data created on test classes, it would be a matter of time before you reach the limit. If your environment is not yet enabled for FAST deploy as discuss in my previous blog post, you will not be able to do regular deployment.

As of right now there is no fool-proof solution for this. However, there are a couple of things I would recommend you check in case you are getting the error message.


  1. Check if your environment is loading bulk data from static resource. I'm not a big fan of the Salesforce documentation because some of the information are vague (at least for me) and having to clarify to support how salesforce computes, let's say a limit is so slow and takes weeks to confirm based on my experience. Basically loading data from static resource using Test.loadData are computed as part of this overall DML row limit.
  2. Are you using Custom Settings as holder of your environment variables? One of the things I learned from previous Dreamforce sessions is that you can use custom settings as holder of environment variables so that you don't need to maintain static values on a class since its hard to redeploy components in Production environment and using custom labels to do this may not be the best solution (and using custom labels for storing such values are not good since it should be used for multi-lingual content). This is a similar pattern used for Java and even .NET that is handy. However you may want to review this pattern because it will be a liability at the end because of the limit.
  3. Consider Multi-Org Setup. I'll be honest, as of right now I haven't implemented this on a client but having said that, having multiple instances definitely means you have separate limits for each of your unrelated applications. If for somehow some of your applications are connected then maybe you can take a look at Salesforce to Salesforce feature. 
  4. Use SeeAllData=true. I don't really recommend this since it slows down processing of test classes and it is not a best practice but it can be a temporary workaround specially if you are loading a lot of test records from your test classes regardless if its coming for custom settings or coded in the class.
  5. Check with if Managed Package will help. Now this is something I'm not sure will work and you may want to check with Salesforce but from what I understand, managed package has its own limits with unmanaged package. (I would appreciate if someone can confirm if it would work or not.)

I hope you find the list above helpful. Let me know if you encounter the same issue and if you have any thoughts on how to fix the issue. In addition, please vote my idea on removing DML row limit for loading data using static resource.

19 June 2014

Salesforce Login Types

For some reason I could not find any public salesforce documentation or KB articles that discusses what each of the login types means in the Login History page. So I asked support to understand each and they provided me with the table below which I'm sharing to help anyone who may be needing it.

Login Type Description
Application UI login
Chatter Communities External User Community User Login
Other Apex API Other Apex API
Partner Product Partner Integration Login
Remote Access 2.0 OAuth 2.0 login ( for example, connected app login)
SAML Chatter Communities 
External User SSO
Community User Login from Single-Sign-On
SAML Idp Initiated SSO SAML Single-Sign-On with login initiated 
from Idp(Identity Provider) side
SAML Sfdc Initiated SSO SAML Single-Sign-On with login initiated 
from Salesforce side, redirect to Idp then 
login after got Idp's SAML response
SYNC Login from SYNC client

16 June 2014

Unlocking the power of custom settings for data loading

Common use case when doing data load is to not to execute anything from the environment such as workflows, validation rules or apex triggers. This can only be achieve if (1) you have migrated only object you are targeting to do data load while workflow and triggers are not yet deployed or (2), workflows and triggers are inactivated which is somehow a hassle to admin or developers as they have to manually deactivate the workflow and worst deploy the inactivated triggers or (3), you explicitly includes user to skip on the workflow criteria or apex codes on triggers. Custom Settings can be used to hold configurations specific to user for skipping such automations.

Below is a sample custom settings I created with 3 fields.


I also created a small apex class that will interface with this custom settings and will be used on apex triggers.

public class AutoSkipSettings {
    
    public static boolean skipTrigger(){
        boolean skipTrigger = false; 
     
        Automation_Skip_Settings__c userSkipSetting = 
             Automation_Skip_Settings__c.getValues(UserInfo.getUserId());
        
        if(userSkipSetting <> null && userSkipSetting.Skip_Trigger__c){
            skipTrigger = true;
        }

        return skipTrigger;
    }
    
}

The apex triggers basically just extracts the custom setting value for the user and return the value of the checkbox. In this case, I'm returning the value of the Skip_Trigger__c field. Now we are ready to use the custom settings on validation and workflow rule criteria and apex trigger.

On the validation or workflow rule, the custom setting fields will be available as a global variable. Note that for workflow rule, you need to select 'formula evaluates to true' on the rule criteria section.


On any apex trigger, use the apex class created above.

trigger TestAccountTrigger on Account (before update) {
    
    if(!AutoSkipSettings.skipTrigger()){
    // do anything here
    }
    
}

Additional Notes:
  • The reason why we used hierarchy type for custom setting is so that we can have a default organization level value. 
  • The custom setting is much better than using custom object so that we save 1 SOQL query on the code and reference the field as global variable on formula





11 August 2012

You have reached the maximum number of 10 object references on Child


The error "You have reached the maximum number of 10 object references in <Object Name>" refers to the maximum number of unique relationship name you can refer to using formula fields meaning the '__r' on the formula.

For example I created 11 lookup fields on the same object. I named it Parent__c, Parent_2__c ... Parent_11__c and want to reference a field on that object for all lookup fields.

This won't be possible as I can only create up to 10 relationship formula fields for these lookup. Trying to create a formula for Parent_11__r will give an error similar to the below: 



So what's the solution?

If you want to populate the hypothetical field Parent_External_ID_11__c (not displayed above) you need to:
  1. Ask salesforce to increase it.  You can request to increase it up to 15 as of summer 12. See notes from product manager and consequence. http://success.salesforce.com/ideaView?id=08730000000gKsbAAE
  2. Remove unused formula fields if possible.
  3. Convert the field to its appropriate field type (in this case I'm just referencing a text so I need to change the field to Text) and then create an Apex Trigger to populate field on the before or after update event as needed.
Please note that you cannot use workflow rule and field update formula if you are referencing the same relationship because its also counted against the limit.

11 May 2011

Parameterized Custom Label

I still remember when custom labels where new and I have a requirement in which I wanted to create a VF email template in which non technical people wouldn't need to edit VF pages to update the email content.

Custom labels first came to mind. However, I thought that multiple custom labels will do the work in which I will concatenate each of them included values I wanted to insert in between words. Then I found out that this is not the best approach as SFDC impose limits to the number of custom labels per org.

Then I found what I'm looking for. It turns out that I can add parameter to custom labels and use the <apex:param> tag to update the value of the parameter in custom labels. To make the story short I created a sample for this entry.

First we create a custom label similar to this:


Take note of the values denoted by the curly braces and the number inside of it. This values empowers the custom labels to accept parameters. Also, you noticed that it start with the number 0. This is the default, as the first parameter you will add on your VF pages <apex:outputText> or any tags that will be displayed on that merge field (I'm calling it merge field).

Next we create a simple VF email template.


For the purpose of this example, I just created an email template that uses the recipientType and relatedToType to Contact. Basically I used the <apex:outputText> tag and add the custom label as its value. Then inside the <apex:outputText> tag, I added some <apex:param> tags with values. Note that the first param tag will be the value for the {0} merge field.

When you save the VF email template you will instantly see that the parameters was substituted by the values you added on the tags.

That's it. You have used parameters for your custom labels!

14 April 2011

How to Process Record using List Button and Visualforce

Long ago, if we want to process records from a record list we create a list button that executes a javascript. The javascript would then use the Salesforce AJAX Toolkit and use a merge field called GETRECORDIDS. However this proved to be slow since its running in client side.

The best way to workaround this is to use Visualforce and the StandardSetController.

Let's say for example that we wan't to update a set of contact via a button on the contact list. First we need to create a Visualforce page that uses its standard controller and creating an extension class.

So for example, we create a Visualforce page with the name ContactListUpdate similar to this:

<apex:page standardController="Contact" 
  extensions="ContactListUpdateExtension" 
  recordSetVar="c" action="{!updateContacts}">
    <apex:form >
        <apex:pageMessages />
        <apex:pageBlock >
            <apex:pageBlockButtons >
                <apex:commandButton value="Back" 
                                 action="{!returnPage}"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1">
                The selected contacts were updated. 
                                Please click the back button to return 
                                to the previous page.
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Take note of the 'RecordSetVar' attributes. Since we will be using the StandardSetController on our controller extension, then it is required.

Then we create our controller extension:

public class ContactListUpdateExtension {
  static string SECONDARY_CONTACT = 'Secondary';
  Contact[] arryContact;
  PageReference pgReturnPage;
  
  // Constructor
  public ContactListUpdateExtension(ApexPages.StandardSetController 
                                   cntlr){
    arryContact = cntlr.getSelected();
    
    // Build the return page 
    String returnUrl = ApexPages.currentPage().
      getParameters().get('retUrl');
    pgReturnPage = new PageReference(returnUrl);
        pgReturnPage.setRedirect(true);
  } 
  
  public void updateContacts(){
    List<Contact> lstContactUpdate = new List<Contact>();
    
    for(Contact c: arryContact){
      c.Level__c = SECONDARY_CONTACT;
      lstContactUpdate.add(c);
    }
    
    Database.Saveresult[] arryResult = 
       Database.update(lstContactUpdate);
    for(Database.SaveResult sResult : arryResult){
      if(!sResult.isSuccess()){
        Database.Error errMsg = sResult.getErrors()[0];
        ApexPages.addMessage(
           new ApexPages.Message(
              ApexPages.Severity.ERROR,
              errMsg.getMessage()));
      }
    }
  }
  
  public PageReference returnPage(){
    return pgReturnPage;
  }
}

In this example I am updating the contacts custom field Level__c to a value 'Secondary'.

As you can see, the constructor parameter accepts the ApexPages.StandardSetController type. This will help us access the selected records by accessing the getSelected() property.

We can now create a List Button whose content source = 'Visualforce page' and refer the previously created Visualforce page. You must also note that we want to have user the ability to select multiple records so we need to tick the 'Display Checkboxes (for Multi-Record Selection)' checkbox.




That's it. You are now processing multiple records on a List Button using Visualforce. Note that you need to add this button to its appropriate page layouts.

31 March 2011

Adding a checkbox on a PageBlockTable

One of the common use cases I experienced developing customization in Salesforce is the ability for end user to selected multiple records from a list and process them. In Salesforce you can do this via client-side scripting using JavaScript. However, it is slow and you don't really have full control of the selected records specially when your doing multi-paging list.

The best approach I believed on doing this is to create an Apex wrapper class. The wrapper class is a class that will represent data for your table with additional properties. An example of using wrapper class is when you want to display an accounts and then select them using a checkboxes. Let's see how we approach that below.

We first create a wrapper class similar to this:

public class AccountWrapperCls {
     public Boolean isSelected {get;set;}
     public Account cAccount {get;set;}

     public AccountWrapperCls(Account cAccount){
          this.cAccount = cAccount;
     }
}

As you can see above, the class contains an account and a boolean property. The isSelected property will be referenced by our Visualforce page and will be rendered as a checkbox. To use this wrapper class we need to create a Visualforce controller for our page that will use the class above.

public class MyAccountListCntrlr {
     // PROPERTIES
     public List<AccountWrapperCls> acctList {get;set;}
     public Set<String> selAccountNames {get;set;}
     public Boolean hasSelAcct {get;set;}

     // CONSTRUCTOR
     public MyAccountListCntrlr(){
          acctList = new List<AccountWrapperCls>();
          selAccountNames = new Set<String>();

          for(Account a : [SELECT AccountNumber, Name 
          FROM Account WHERE AccountNumber != NULL 
          LIMIT 5]){
               acctList.add(new AccountWrapperCls(a));
          }
     }

     // METHODS
     public void displaySelectedAccountNumbers(){
          selAccountNames.clear();
          hasSelAcct = false;
          for(AccountWrapperCls cWrapper : acctList){
               if(cWrapper.isSelected){
                    hasSelAcct = true;
                    selAccountNames.add(cWrapper.cAccount.
                             AccountNumber);
               }
          }
     }
}

As you can see above, we created a list of type AccountWrapperCls which represents the account record and the additional isSelected property. Please note that we add a method called displaySelectedAccountNumbers() which gets all the account records whose isSelected value is set to TRUE. It also adds those selected account's account number to a set variable we defined in our class which we will use to display account numbers on the page.

Below is our Visualforce page:

<apex:page controller="MyAccountListCntrlr" tabStyle="Account">
   <apex:form >
      <apex:pageBlock title="Account List">
         <apex:pageBlockButtons >
            <apex:commandButton 
               value="Show Selected Accounts" 
               action="{!displaySelectedAccountNumbers}"/>
         </apex:pageBlockButtons>

         <!-- ACCOUNT LIST -->
         <apex:pageBlockTable 
           value="{!acctList}" 
           var="acctWrapper">
            <apex:column >
               <apex:inputCheckbox 
                 value="{!acctWrapper.isSelected}"/>
            </apex:column> 
            <apex:column 
              value="{!acctWrapper.cAccount.AccountNumber}"/>
            <apex:column 
              value="{!acctWrapper.cAccount.Name}"/>
         </apex:pageBlockTable>

         <!-- SELECTED ACCOUNT INFO -->
         <apex:pageBlockSection >
            <apex:outputPanel 
              layout="block" 
              rendered="{!hasSelAcct}">
               <apex:outputText 
                 value="Below are the selected account:"/>
               <br/>
               <apex:outputText 
                 value="{!selAccountNames}"/>
             </apex:outputPanel>
             <apex:outputPanel layout="block" 
               rendered="{!NOT(hasSelAcct)}">
                <br/>
                <apex:outputText value="No account selected."/>
             </apex:outputPanel>
         </apex:pageBlockSection>
      </apex:pageBlock>
   </apex:form>
</apex:page>

Note that we referenced our list variable while using the properties of our wrapper class in the controller .