/*
|
* Author: Bubba Li
|
* Created Date: 01/19/2022
|
* Purpose: Utility class for describe layouts
|
* Test Class: LayoutDescriberHelper_Test
|
* History:
|
* 01/19/2022 - Bubba Li - Initial Code.
|
*
|
* */
|
|
public class LayoutDescriberHelper {
|
public static String urlPrefixToUse { get; set; }
|
public static List<String> requiredFieldAPIList { get; set; }
|
public static Map<String, String> fieldAPIToLabelMap { get; set; }
|
public static Set<String> CaseWebFields = new Set<String>{
|
'SuppliedCompany',
|
'SuppliedName',
|
'SuppliedEmail',
|
'SuppliedPhone'
|
};
|
public static Set<String> ConcatenationNameSType = new Set<String>{
|
'Lead',
|
'Contact'
|
};
|
public static LayoutWrapper describeSectionWithFieldsWrapper(
|
Id recordTypeId,
|
String objectType,
|
String userMode
|
) {
|
if (String.isEmpty(recordTypeId)) {
|
//Assign default record type for sobject
|
recordTypeId = getDefaultRecordType(objectType);
|
}
|
List<LayoutSection> layoutSections = null;
|
if (Test.isRunningTest()) {
|
layoutSections = (List<LayoutSection>) Json.deserialize(
|
'[{"useHeader":true,"name":"Information","layoutFields":[{"isRequired":false,"isPlaceHolder":false,"fieldType":"reference","fieldLabel":"Owner","fieldAPI":"OwnerId","editableField":false,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"string","fieldLabel":"文件名","fieldAPI":"FileName__c","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"picklist","fieldLabel":"Currency","fieldAPI":"CurrencyIsoCode","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"string","fieldLabel":"预览链接","fieldAPI":"ViewLink__c","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":true,"fieldType":"","fieldLabel":"","fieldAPI":"","editableField":false,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"string","fieldLabel":"下载链接","fieldAPI":"DownloadLink__c","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":true,"fieldType":"","fieldLabel":"","fieldAPI":"","editableField":false,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"string","fieldLabel":"父级目录","fieldAPI":"ParentRecordId__c","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":true,"fieldType":"","fieldLabel":"","fieldAPI":"","editableField":false,"defaultValue":null},{"isRequired":false,"isPlaceHolder":false,"fieldType":"string","fieldLabel":"AWS File Key","fieldAPI":"AWS_File_Key__c","editableField":true,"defaultValue":null},{"isRequired":false,"isPlaceHolder":true,"fieldType":"","fieldLabel":"","fieldAPI":"","editableField":false,"defaultValue":null}],"columns":2,"allowCollapse":false}]',
|
List<LayoutSection>.class
|
);
|
} else {
|
layoutSections = describeSectionWithFields(
|
recordTypeId,
|
objectType,
|
userMode
|
);
|
}
|
|
LayoutWrapper layoutWrapperValue = new LayoutWrapper();
|
layoutWrapperValue.layoutSections = layoutSections;
|
layoutWrapperValue.requiredFieldAPIList = requiredFieldAPIList;
|
layoutWrapperValue.fieldAPIToLabelMap = fieldAPIToLabelMap;
|
system.debug('required API List:' + JSON.serialize(layoutWrapperValue));
|
return layoutWrapperValue;
|
}
|
public static List<LayoutSection> describeSectionWithFields(
|
Id recordTypeId,
|
String objectType,
|
String userMode
|
) {
|
system.debug(
|
'record type id ===>' +
|
recordTypeId +
|
' object type===>' +
|
objectType +
|
' userMode===>' +
|
userMode
|
);
|
List<LayoutSection> layoutSections;
|
Map<String, List<LayoutField>> layoutFields;
|
requiredFieldAPIList = new List<String>();
|
fieldAPIToLabelMap = new Map<String, String>();
|
layoutSections = new List<LayoutSection>();
|
String theRespBody = getLayoutSchema(recordTypeId, objectType, userMode);
|
Map<String, Object> layoutSection = (Map<String, Object>) JSON.deserializeUntyped(
|
theRespBody
|
);
|
Map<String, object> m = new Map<String, object>();
|
if (String.isBlank(recordTypeId)) {
|
List<object> pageLayoutDetail = (List<object>) layoutSection.get(
|
'layouts'
|
);
|
System.debug(
|
'Page Layout Section Detail:' + JSON.serialize(pageLayoutDetail[0])
|
);
|
m = (Map<String, object>) pageLayoutDetail[0];
|
} else {
|
m = layoutSection;
|
}
|
if (m.containsKey('editLayoutSections')) {
|
List<object> targetLayout = (List<object>) m.get('editLayoutSections');
|
for (object sectionObject : targetLayout) {
|
Map<String, object> section = (Map<String, object>) sectionObject;
|
String sectionH = (String) section.get('heading');
|
boolean useH = (boolean) section.get('useHeading');
|
integer columns = (integer) section.get('columns');
|
boolean useCollapse = (boolean) section.get('useCollapsibleSection');
|
LayoutSection ls = new LayoutSection();
|
ls.Name = sectionH;
|
ls.useHeader = useH;
|
ls.columns = columns;
|
ls.allowCollapse = useCollapse;
|
ls.layoutFields = new List<LayoutField>();
|
layoutSections.add(ls);
|
List<object> layoutRows = (List<object>) section.get('layoutRows');
|
system.debug('layout rows ====> ' + layoutRows);
|
for (Object itemObject : layoutRows) {
|
Map<String, object> item = (Map<String, object>) itemObject;
|
List<object> layoutItem = (List<object>) item.get('layoutItems');
|
boolean priorFieldLayoutAdded = true; //initially true
|
for (object fieldItemObject : layoutItem) {
|
Map<String, object> fields = (Map<String, object>) fieldItemObject;
|
List<object> layoutComponents = (List<object>) fields.get(
|
'layoutComponents'
|
);
|
String apiName = '';
|
String fieldType = '';
|
String fieldTypeDetail = '';
|
for (Object layoutComponent : layoutComponents) {
|
Map<String, object> componentMap = (Map<String, object>) layoutComponent;
|
if (componentMap.containsKey('value')) {
|
apiName = (String) componentMap.get('value');
|
}
|
|
if (componentMap.containsKey('type')) {
|
fieldType = (String) componentMap.get('type');
|
}
|
|
if (componentMap.containsKey('details')) {
|
Map<String, object> detailsMap = (Map<String, object>) componentMap.get(
|
'details'
|
);
|
boolean calculatedField = (boolean) detailsMap.get(
|
'calculated'
|
);
|
boolean autoNumberField = (boolean) detailsMap.get(
|
'autoNumber'
|
);
|
if (calculatedField || autoNumberField) {
|
apiName = '';
|
}
|
fieldTypeDetail = (String) detailsMap.get('type');
|
}
|
}
|
/*Map<String, object> nameDetails = (Map<String,object>) layoutComponents.get('Name');*/
|
String fieldLabel = (String) fields.get('label');
|
boolean placeholderF = (boolean) fields.get('placeholder');
|
boolean isEditable =
|
(boolean) fields.get('editableForUpdate') ||
|
(boolean) fields.get('editableForNew'); // Check the editable prop
|
if ((apiName != '' && fieldType == 'Field') || (placeholderF)) {
|
if (userMode == 'classic' && fieldTypeDetail == 'address') {
|
String fieldLabelPrefix = fieldLabel.split(' ')[0] == 'Address'
|
? ''
|
: fieldLabel.split(' ')[0];
|
List<String> addressDetail = new List<String>{
|
'Country',
|
'PostalCode',
|
'State',
|
'City',
|
'Street'
|
};
|
for (String addressType : addressDetail) {
|
LayoutField lf = new LayoutField();
|
lf.isRequired = (Boolean) fields.get('required');
|
lf.isPlaceHolder = placeholderF;
|
lf.editableField = isEditable;
|
lf.fieldAPI = fieldLabelPrefix + addressType;
|
|
lf.fieldLabel = fieldLabelPrefix + ' ' + addressType;
|
lf.fieldType = 'string';
|
if (ls.Name != '' || layoutSections.size() == 1) {
|
ls.layoutFields.add(lf);
|
} else if (layoutSections.size() - 2 >= 0) {
|
layoutSections.get(layoutSections.size() - 2)
|
.layoutFields.add(lf);
|
}
|
if (lf.isRequired) {
|
system.debug(lf.fieldAPI + ' is required');
|
requiredFieldAPIList.add(lf.fieldAPI);
|
}
|
if (string.isBlank(lf.fieldAPI)) {
|
system.debug('==================================2');
|
continue;
|
} else {
|
fieldAPIToLabelMap.put(lf.fieldAPI, lf.fieldLabel);
|
}
|
}
|
continue;
|
}
|
if (
|
userMode == 'classic' &&
|
apiName == 'Name' &&
|
ConcatenationNameSType.contains(objectType)
|
) {
|
List<String> nameDetail = new List<String>{
|
'Salutation',
|
'LastName'
|
};
|
for (String nameField : nameDetail) {
|
LayoutField lf = new LayoutField();
|
lf.isRequired = (Boolean) fields.get('required');
|
if (nameField == 'Salutation') {
|
lf.isRequired = false;
|
}
|
lf.isPlaceHolder = placeholderF;
|
lf.editableField = isEditable;
|
lf.fieldAPI = nameField;
|
lf.fieldLabel = nameField;
|
lf.fieldType = 'string';
|
if (ls.Name != '' || layoutSections.size() == 1) {
|
ls.layoutFields.add(lf);
|
} else if (layoutSections.size() - 2 >= 0) {
|
layoutSections.get(layoutSections.size() - 2)
|
.layoutFields.add(lf);
|
}
|
if (lf.isRequired) {
|
system.debug(lf.fieldAPI + ' is required');
|
requiredFieldAPIList.add(lf.fieldAPI);
|
}
|
if (string.isBlank(lf.fieldAPI)) {
|
system.debug('==================================3');
|
continue;
|
} else {
|
fieldAPIToLabelMap.put(lf.fieldAPI, lf.fieldLabel);
|
}
|
}
|
continue;
|
}
|
if (objectType == 'Case' && CaseWebFields.contains(apiName)) {
|
continue;
|
}
|
LayoutField lf = new LayoutField();
|
lf.isRequired = (Boolean) fields.get('required');
|
lf.isPlaceHolder = placeholderF;
|
lf.editableField = isEditable;
|
lf.fieldAPI = apiName;
|
lf.fieldLabel = fieldLabel;
|
lf.fieldType = fieldTypeDetail;
|
if (ls.Name != '' || layoutSections.size() == 1) {
|
ls.layoutFields.add(lf);
|
} else if (layoutSections.size() - 2 >= 0) {
|
layoutSections.get(layoutSections.size() - 2)
|
.layoutFields.add(lf);
|
}
|
if (lf.isRequired) {
|
system.debug(lf.fieldAPI + ' is required');
|
requiredFieldAPIList.add(lf.fieldAPI);
|
}
|
if (string.isBlank(lf.fieldAPI)) {
|
system.debug('==================================1');
|
continue;
|
} else {
|
fieldAPIToLabelMap.put(lf.fieldAPI, lf.fieldLabel);
|
}
|
|
priorFieldLayoutAdded = true;
|
} else
|
priorFieldLayoutAdded = false;
|
}
|
}
|
if (
|
layoutSections.get(layoutSections.size() - 1).layoutFields.size() <= 0
|
) {
|
layoutSections.remove(layoutSections.size() - 1);
|
}
|
}
|
}
|
System.debug('Layout Section Result:' + JSon.serialize(layoutSections));
|
system.debug('required API List:' + JSON.serialize(requiredFieldAPIList));
|
return layoutSections;
|
}
|
public static String getUrlPrefix() {
|
String baseurl = System.URL.getOrgDomainUrl().getHost();
|
system.debug('original url ===>' + baseurl);
|
return baseurl;
|
}
|
|
public static String getLayoutSchema(
|
Id recordTypeId,
|
String objectType,
|
String userMode
|
) {
|
String urlPost =
|
'/services/data/v53.0/sobjects/' +
|
objectType +
|
'/describe/layouts/';
|
if (String.isNotEmpty(recordTypeId) && String.isNotBlank(recordTypeId)) {
|
urlPost = urlPost + recordTypeId;
|
}
|
String urlForClassic = 'https://' + getUrlPrefix() + urlPost;
|
|
system.debug('URL Post:' + urlForClassic);
|
HttpResponse resp = null;
|
HttpRequest req = new HttpRequest();
|
req.setMethod('GET');
|
if (userMode == 'lightning') {
|
req.setEndPoint('callout:SF_Rest_API' + urlPost);
|
system.debug('callout:SF_Rest_API' + urlPost);
|
} else if (userMode == 'classic') {
|
req.setEndpoint(urlForClassic);
|
req.setHeader('Authorization', 'Bearer ' + UserInfo.getsessionid());
|
}
|
Http client = new Http();
|
resp = client.send(req);
|
system.debug('Schema Body:' + JSON.serialize(resp.getBody()));
|
return resp.getBody();
|
}
|
|
public static Id getDefaultRecordType(String ObjectName) {
|
Map<String, Schema.SObjectType> GlobalDescribeMap = Schema.getGlobalDescribe();
|
Schema.SObjectType obj = GlobalDescribeMap.get(ObjectName);
|
Schema.DescribeSObjectResult describeResult = obj.getDescribe();
|
List<Schema.RecordTypeInfo> rtInfos = describeResult.getRecordTypeInfos();
|
for (Schema.RecordTypeInfo rtInfo : rtInfos) {
|
if (rtInfo.DefaultRecordTypeMapping) {
|
return rtInfo.getRecordTypeId();
|
}
|
}
|
return null;
|
}
|
public class LayoutWrapper {
|
@AuraEnabled
|
public List<LayoutSection> layoutSections { get; set; }
|
@AuraEnabled
|
public List<String> requiredFieldAPIList { get; set; }
|
@AuraEnabled
|
public Map<String, String> fieldAPIToLabelMap { get; set; }
|
}
|
public class LayoutSection {
|
@AuraEnabled
|
public boolean useHeader { get; set; }
|
@AuraEnabled
|
public String name { get; set; }
|
@AuraEnabled
|
public boolean allowCollapse { get; set; }
|
@AuraEnabled
|
public integer columns { get; set; }
|
@AuraEnabled
|
public List<LayoutField> layoutFields { get; set; }
|
}
|
|
public class LayoutField {
|
@AuraEnabled
|
public String fieldAPI { get; set; }
|
@AuraEnabled
|
public String fieldLabel { get; set; }
|
@AuraEnabled
|
public String fieldType { get; set; }
|
@AuraEnabled
|
public boolean editableField { get; set; }
|
@AuraEnabled
|
public boolean isRequired { get; set; }
|
@AuraEnabled
|
public boolean isPlaceHolder { get; set; }
|
@AuraEnabled
|
public String defaultValue { get; set; }
|
}
|
public static Integer ControllerUtil() {
|
Integer i = 0;
|
|
return i;
|
}
|
}
|