Skip to content

Instantly share code, notes, and snippets.

@Nahumancer
Created August 10, 2018 03:56
Show Gist options
  • Save Nahumancer/154e6e8cd8b3b97d087079c8c06739f4 to your computer and use it in GitHub Desktop.
Save Nahumancer/154e6e8cd8b3b97d087079c8c06739f4 to your computer and use it in GitHub Desktop.
Class by Benj Kamn. Stored here for personal reference/quick access.
/*
* Apex doesn't expose dependent picklist info directly, but it's possible to expose.
* Approach:
* * Schema.PicklistEntry doesn't expose validFor tokens, but they are there, and can be accessed by serializing to JSON
* (and then for convenience, deserializing back into an Apex POJO)
* * validFor tokens are converted from base64 representations (e.g. gAAA) to binary (100000000000000000000)
* each character corresponds to 6 bits, determined by normal base64 encoding rules.
* * The binary bits correspond to controlling values that are active - e.g. in the example above, this dependent option
* is available for the first controlling field only.
*
* by Benj Kamm, 2017
* CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/us/)
*/
public class HL_FieldDescribeUtil {
public static Map<String, List<String>> getDependentOptionsImpl(Schema.SObjectField theField, Schema.SObjectField ctrlField) {
// validFor property cannot be accessed via a method or a property,
// so we need to serialize the PicklistEntry object and then deserialize into a wrapper.
List<Schema.PicklistEntry> contrEntries = ctrlField.getDescribe().getPicklistValues();
List<PicklistEntryWrapper> depEntries =
HL_FieldDescribeUtil.wrapPicklistEntries(theField.getDescribe().getPicklistValues());
// Set up the return container - Map<ControllingValue, List<DependentValues>>
Map<String, List<String>> objResults = new Map<String, List<String>>();
List<String> controllingValues = new List<String>();
for (Schema.PicklistEntry ple : contrEntries) {
String label = ple.getLabel();
objResults.put(label, new List<String>());
controllingValues.add(label);
}
for (PicklistEntryWrapper plew : depEntries) {
String label = plew.label;
String validForBits = base64ToBits(plew.validFor);
for (Integer i = 0; i < validForBits.length(); i++) {
// For each bit, in order: if it's a 1, add this label to the dependent list for the corresponding controlling value
String bit = validForBits.mid(i, 1);
if (bit == '1') {
objResults.get(controllingValues.get(i)).add(label);
}
}
}
return objResults;
}
// Convert decimal to binary representation (alas, Apex has no native method :-(
// eg. 4 => '100', 19 => '10011', etc.
// Method: Divide by 2 repeatedly until 0. At each step note the remainder (0 or 1).
// These, in reverse order, are the binary.
public static String decimalToBinary(Integer val) {
String bits = '';
while (val > 0) {
Integer remainder = Math.mod(val, 2);
val = Integer.valueOf(Math.floor(val / 2));
bits = String.valueOf(remainder) + bits;
}
return bits;
}
// Convert a base64 token into a binary/bits representation
// e.g. 'gAAA' => '100000000000000000000'
public static String base64ToBits(String validFor) {
if (String.isEmpty(validFor)) return '';
String validForBits = '';
for (Integer i = 0; i < validFor.length(); i++) {
String thisChar = validFor.mid(i, 1);
Integer val = base64Chars.indexOf(thisChar);
String bits = decimalToBinary(val).leftPad(6, '0');
validForBits += bits;
}
return validForBits;
}
private static final String base64Chars = '' +
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
'abcdefghijklmnopqrstuvwxyz' +
'0123456789+/';
private static List<PicklistEntryWrapper> wrapPicklistEntries(List<Schema.PicklistEntry> PLEs) {
return (List<PicklistEntryWrapper>)
JSON.deserialize(JSON.serialize(PLEs), List<PicklistEntryWrapper>.class);
}
public class PicklistEntryWrapper {
public String active {get; set;}
public String defaultValue {get; set;}
public String label {get; set;}
public String value {get; set;}
public String validFor {get; set;}
}
}
@Nahumancer
Copy link
Author

Nahumancer commented Aug 10, 2018

This is how you get a list of picklist values from the API:

List<String> options = new List<String>();
Schema.DescribeFieldResult fieldResult = Account.Parent_Picklist__c.getDescribe();
List<Schema.PicklistEntry> pList = fieldResult.getPicklistValues();
for (Schema.PicklistEntry p: pList) {
    options.add(p.getLabel());
}
return options;

This is how you get "children" side values of a dependent picklist

    public static List<String> getDependentPicklistValues(String parentValue){
        List<String> options = new List<String>();
        if(parentValue != null){
            Map<String, List<String>> results = HL_FieldDescribeUtil.getDependentOptionsImpl(getSObjectField('Account.ChildPicklist__c'), getSObjectField('Account.Parent_Picklist__c'));
            for(String auxValue : results.get(parentValue)){
                options.add(auxValue);
            }
        }
        return options;
    }

    private static Schema.SObjectField getSObjectField(String nameAux){
        //String productSubCategoryString = fieldName;
        List<String> splitString = nameAux.split('\\.');
        // store the object/field names
        String objectName = splitString[0];
        String fieldName = splitString[1];
        // get the SObjectType
        Schema.SObjectType objectType = Schema.getGlobalDescribe().get(objectName);
        // get the fields on the object
        Map<String, SObjectField> fieldMap = objectType.getDescribe().fields.getMap();
        // The key to the map is the api name of the field
        Schema.SobjectField theField = fieldMap.get(fieldName);
        return theField;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment