LoginSignup
5
5

More than 5 years have passed since last update.

Apexで連動項目の選択肢を取得する方法

Last updated at Posted at 2016-02-05

連動項目の選択リストを動的に取得・作成したい場合にAPIコールでのみ利用できるValidForをApexでも利用できるようにしてしまった猛者がいたので、簡単に使えるように少し修正してみました。

こんな感じで使えます。
SomeObjectというオブジェクトにctrlPicklistdepPicklistという選択リストがあるとして、ctrlPicklistが制御項目、depPicklistが連動項目と仮定しています。

Example.apxc
public class Example {
    private static String INITIAL_VALUE = '';
    // 選択リストで選択された値が格納される変数
    public SomeObject objectInstance {get; set;}

    public List<SelectOption> DependentPickListOptions{
        get{
            List<SelectOption> options = new List<SelectOption>();

            // 選択リストの一番上にデフォルトの選択値を設定
            options.add(new SelectOption(INITIAL_VALUE, '-- なし --'));

            // 制御項目ctrlPicklistが選択されている時に連動項目depPicklistで選べる選択肢を取得する。
            if( this.objectInstance.ctrlPicklist != null || this.objectInstance.ctrlPicklist != INITIAL_VALUE ){
                List<DepPickListCtrl.TPicklistEntry> tPicklistEntries = 
                    DepPickListCtrl.GetDependentOptions('SomeObject','ctrlPicklist','depPicklist').get(this.objectInstance.ctrlPicklist);

                for( DepPickListCtrl.TPicklistEntry e : tPicklistEntries ){
                    options.add(new SelectOption(e.value, e.label));
                }
            }
            return options;
        }
    }

    // コンストラクタ
    public Example(){
        this.objectInstance = new SomeObject();
    }     
}

下のApexクラスを同じ組織に一つ追加します。

DepPickListCtrl.apxc
/* Reference
 * Great thanks to Neel
 * http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/
 */

public class DepPickListCtrl {
    public static Map<String,List<DepPickListCtrl.TPicklistEntry>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName){
        Map<String,List<DepPickListCtrl.TPicklistEntry>> objResults = new Map<String,List<DepPickListCtrl.TPicklistEntry>>();
        //get the string to sobject global map
        Map<String,Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe();
        if (!objGlobalMap.containsKey(pObjName))
            return objResults;
        //get the type being dealt with
        Schema.SObjectType pType = objGlobalMap.get(pObjName);
        Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();
        //verify field names
        if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName))
            return objResults;     
        //get the control values   
        List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
        //get the dependent values
        List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();
        //iterate through the values and get the ones valid for the controlling field name
        DepPickListCtrl.Bitset objBitSet = new DepPickListCtrl.Bitset();
        //set up the results
        for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){          
            //get the pointer to the entry
            Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex];
            //get the label
            String pControllingLabel = ctrl_entry.getLabel();
            //create the entry with the label
            objResults.put(pControllingLabel,new List<DepPickListCtrl.TPicklistEntry>());
        }
        //cater for null and empty
        objResults.put('',new List<DepPickListCtrl.TPicklistEntry>());
        objResults.put(null,new List<DepPickListCtrl.TPicklistEntry>());
        //check the dependent values
        for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){          
            //get the pointer to the dependent index
            Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex];
            //get the valid for
            String pEntryStructure = JSON.serialize(dep_entry);                
            DepPickListCtrl.TPicklistEntry objDepPLE = (DepPickListCtrl.TPicklistEntry)JSON.deserialize(pEntryStructure, DepPickListCtrl.TPicklistEntry.class);
            //if valid for is empty, skip
            if (objDepPLE.validFor==null || objDepPLE.validFor==''){
                continue;
            }
            //iterate through the controlling values
            for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){    
                if (objBitSet.testBit(objDepPLE.validFor,pControllingIndex)){                
                    //get the label
                    String pControllingValue = ctrl_ple[pControllingIndex].getValue();
                    objResults.get(pControllingValue).add(objDepPLE);
                }
            }
        } 
        return objResults;
    }
    public class TPicklistEntry{
        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;}
        public TPicklistEntry(){
        }
    }
    private class Bitset{
        public Map<String,Integer> AlphaNumCharCodes {get;set;}
        public Map<String, Integer> Base64CharCodes { get; set; }
        public Bitset(){
            LoadCharCodes();
        }
        //Method loads the char codes
        private void LoadCharCodes(){
            AlphaNumCharCodes = new Map<String,Integer>{
                '!'=>33,'”'=>34,'#'=>35,'$'=>36,'%'=>37,'&'=>38,'\''=>39,'('=>40,')'=>41,'*'=>42,'+'=>43,','=>44,'-'=>45,
                '.'=>46,'/'=>47,'0'=>48,'1'=>49,'2'=>50,'3'=>51,'4'=>52,'5'=>53,'6'=>54,'7'=>55,
                '8'=>56,'9'=>57,':'=>58,';'=>59,'<'=>60,'='=>61,'>'=>62,'?'=>63,'@'=>64,
                'A'=>65,'B'=>66,'C'=>67,'D'=>68,'E'=>69,'F'=>70,'G'=>71,'H'=>72,'I'=>73,'J'=>74,
                'K'=>75,'L'=>76,'M'=>77,'N'=>78,'O'=>79,'P'=>80,'Q'=>81,'R'=>82,'S'=>83,'T'=>84,
                'U'=>85,'V'=> 86,'W'=>87,'X'=>88,'Y'=>89,'Z'=>90
            };
            Base64CharCodes = new Map<String, Integer>();
            //lower case
            Set<String> pUpperCase = AlphaNumCharCodes.keySet();
            for(String pKey : pUpperCase){
                //the difference between upper case and lower case is 32
                AlphaNumCharCodes.put(pKey.toLowerCase(),AlphaNumCharCodes.get(pKey)+32);
                //Base 64 alpha starts from 0 (The ascii charcodes started from 65)
                Base64CharCodes.put(pKey,AlphaNumCharCodes.get(pKey) - 65);
                Base64CharCodes.put(pKey.toLowerCase(),AlphaNumCharCodes.get(pKey) - (65) + 26);
            }
            //numerics
            for (Integer i=0; i<=9; i++){
                AlphaNumCharCodes.put(string.valueOf(i),i+48);
                //base 64 numeric starts from 52
                Base64CharCodes.put(string.valueOf(i), i + 52);
            }
        }
        public Boolean testBit(String pValidFor,Integer n){
            //the list of bytes
            List<Integer> pBytes = new List<Integer>();
            //multiply by 6 since base 64 uses 6 bits
            Integer bytesBeingUsed = (pValidFor.length() * 6)/8;
            //will be used to hold the full decimal value
            Integer pFullValue = 0;
            //must be more than 1 byte
            if (bytesBeingUsed <= 1)
                return false;
            //calculate the target bit for comparison
            Integer bit = 7 - (Math.mod(n,8)); 
            //calculate the octet that has in the target bit
            Integer targetOctet = (bytesBeingUsed - 1) - (n >> bytesBeingUsed); 
            //the number of bits to shift by until we find the bit to compare for true or false
            Integer shiftBits = (targetOctet * 8) + bit;
            //get the base64bytes
            for(Integer i=0;i<pValidFor.length();i++){
                //get current character value
                pBytes.Add((Base64CharCodes.get((pValidFor.Substring(i, i+1)))));
            }
            //calculate the full decimal value
            for (Integer i = 0; i < pBytes.size(); i++)
            {
                Integer pShiftAmount = (pBytes.size()-(i+1))*6;//used to shift by a factor 6 bits to get the value
                pFullValue = pFullValue + (pBytes[i] << (pShiftAmount));
            }
            //& is to set the same set of bits for testing
            //shift to the bit which will dictate true or false
            Integer tBitVal = ((Integer)(Math.Pow(2, shiftBits)) & pFullValue) >> shiftBits;
            return  tBitVal == 1;
        }
    }
}

動作確認

V35

5
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5