Best Practices & utility-class

More Great Stuff!

http://www.salesforcefast.com/p/best-practices.html

********************************************************

Best Practices

Apex Development

  1. Comment your code.
  2. Use three spaces for indentation.
  3. Always include try-catch block in each method.
  4. Throw your own custom exceptions.
  5. Use addError() to manage DML errors inside of classes and triggers.
  6. Never declare a variable inside a loop.
  7. Never execute SOQL inside a loop.
  8. Never perform DML inside a loop.
  9. Never, never, never hard-code an ID inside code.
  10. Large queries function better in a SOQL for loop – if, of course, you don’t need to use that list anywhere outside of that loop.
  11. Anticipate governor limit errors and add code to manage them before they happen – you cannot trap a governor limit error in a try-catch block.
  12. SOQL keywords are upper-cased.
  13. Don’t include more fields on your SOQL query than you actually need.
  14. Make error messages polite and conversation – not “Missing required field” but more like “Sorry, but you have to supply a value for the Status field to save this record.”
  15. When querying RecordType, never use RecordType.Name; always use RecordType.DeveloperName and RecordType.SobjectType.

Apex Trigger Development

  1. Only have one trigger per object. It uses fewer resources and when there are multiple triggers on the object for a given action, we have no way to know in what order those triggers will fire.
  2. Try to keep logic out of triggers – encapsulate it in separate Apex classes. There are many, many more opportunities for code re-use in Apex classes than in triggers.
  3. Execute DML against lists, sets, or even maps of records rather than against individual records.
  4. Learn to manage lists of lists, lists of maps, maps of maps, maps of sets, and other complex collection logic for the highest efficiency in trigger logic.

Apex Unit Tests

  1. Put unit tests inside your Apex classes for maximum convenience. If you follow the best practice for creating Apex classes to encapsulate the logic for your triggers, you won’t need any separate unit test classes to manage.
  2. Never reference an ID inside a test class.
  3. Never assume that any data exists in the database. You should be able to upload your Apex code into a blank sandbox and all test classes should run flawlessly.
  4. Put in assertions to validate that your code is running the way you think it should.
  5. Use test.startTest() and test.stopTest() to set up a separate transaction to manage governor limits.
  6. If your unit test does not include test.startTest() and test.stopTest(), you’re doing it wrong.
  7. Don’t just test a single record – test 200 records and validate that you can handle bulk transactions.

Visualforce Development

  1. Never hard-code picklists in your VF page – use the controller instead. If a picklist is truly hard-coded, set up a static list you can reference from a static class.
  2. Always show which fields are required using XXX.
  3. If you re-use your CSS and Javascript at all, create static resources for them and include them as needed.
  4. Mark variables as transient to reduce heap size.
  5. Put Javascript at the bottom of the page to improve page load time.
  6. Always use $ObjectType to make your page change-resistant.
  7. Make error messages polite and conversation – not “Missing required field” but more like “Sorry, but you have to supply a value for the Status field to save this record.”

Database Design

  1. Always add a Description to your new custom object. Use a consistent pattern for this Description that explains what business need the object is intended to fulfill.
  2. Pay attention to your object name. You have to get the Plural Label right or else your Tab label won’t come out right. Too often I see that the Object Name is plural, too. Don’t – it makes writing code difficult when you’re not sure how to spell the name of the object.
  3. Pay attention to the relationships between parent and child. If you will need to know who the Owner of a child record is, then you cannot set up a Master-Detail relationship between parent and child.
  4. Pay attention to the Sharing Setting when you do set up a Master-Detail relationship.
  5. Always put in bubble help. If you leave it blank, you look sloppy. (If you really don’t know what the field is for, why are you adding it?) I prefer the question format for bubble help. For example, if the field I was adding to the Account object was “SLA”, and its picklist values were “Gold”, “Silver”, and “Bronze”, then I would write “What is level of Service Level Agreement (SLA) has this Account purchased?”
  6. If you’re not the developer, don’t ever change the API Name. Frequently you can’t because it is referenced from some code somewhere, but it’s a good rule to follow globally because you never know what you’re going to break by changing it.

Release Management

  1. All Apex development happens in the sandbox, if you have one.
  2. Since all Apex development happens in the sandbox, that means everything else happens in the sandbox too.
  3. Including unit, interface, and system testing.
  4. If you are doing system testing without a test plan, you aren’t really doing system testing. (I call this smoke testing, after a story my father told me about working as an engineer in the 1960’s. Here’s how they “smoke-tested” a new component: they turned it on. If it didn’t start smoking, it was ready for real testing.)
  5. If you have good use cases or business requirements, writing a test plan is simple. If writing the test plan isn’t simple, then you don’t have good use cases or business requirements.
  6. If you are actually tasking a coder with system testing, you must have a very cheap coder – and if your coder is that cheap, why do you trust him with your code?
  7. If if it works perfectly in the sandbox after a full, documented system test – that doesn’t mean that it will work in production. Test it again.

Naming Conventions

  1. Every organization needs a naming convention. It really doesn’t matter what your naming convention is – it matters that you have one and that everyone follows it.

Security

  1. If you are doing integrations, set up a separate profile that has Modify All, API Enabled, and Password Never Changes but doesn’t have access to any tabs, then set up a dedicated SFDC User with this profile. All integration jobs should use this dedicated SFDC User. Obviously, get this User’s password a tightly-kept secret.
  2. Set up separate profiles for System Administrator and Sales Administrator. Sales Administrators should not have Author Apex or Customize Application.
  3. Everyone who uses Salesforce for Outlook or similar tools must belong to a profile with API Enabled turned on.

 

*********************************************************

 

 

http://www.salesforcefast.com/p/utility-class.html

Great stuff!

=================================================================================
// Object: util
// Author: John Westenhaver
// Comments: Utility code
// =================================================================================

global without sharing class util
{
// ==============================================================================
// RECORD TYPES
// ==============================================================================
// Get the ID for a Record Type, given its Name. Note
// that this is NOT the Developer Name but rather the Name.
global static ID getRecordTypeId(String objType, String name)
{
SObject obj;
Schema.SObjectType targetType = Schema.getGlobalDescribe().get(objType);
if (targetType != null)
{
obj = targetType.newSObject();
Schema.DescribeSObjectResult d = obj.getSObjectType().getDescribe();
if (d != null)
{
map<string, schema.recordtypeinfo=””> rtMap = d.getRecordTypeInfosByName();
if (rtMap != null)
{
Schema.RecordTypeInfo rtInfo = rtMap.get(name);
if (rtInfo != null)
{
return rtInfo.getRecordTypeId();
}
}
}
}
return null;
}

// Testing this is tricky because what if there aren’t any
// record types in the database yet? We will look for any
// existing record type and use that instead.
private static testMethod void testRt()
{
list types =
[SELECT Id, Name, SObjectType FROM RecordType LIMIT 1];
if (types.size() == 1)
{
ID rtId = getRecordTypeId(types[0].SobjectType, types[0].Name);
system.assert(rtId != null && String.valueOf(rtId).length() == 18);
rtId = getRecordTypeId(‘ABC’, ‘DEF’);
system.assert(rtId == null);
}
}

// ==============================================================================
// VISUALFORCE
// ==============================================================================

// Get a list of picklist values from an existing object field.
global static list getPicklistValues(SObject obj, String fld)
{
list options = new list();
// Get the object type of the SObject.
Schema.sObjectType objType = obj.getSObjectType();
// Describe the SObject using its object type.
Schema.DescribeSObjectResult objDescribe = objType.getDescribe();
// Get a map of fields for the SObject
map<string, schema.sobjectfield=””> fieldMap = objDescribe.fields.getMap();
// Get the list of picklist values for this field.
list values =
fieldMap.get(fld).getDescribe().getPickListValues();
// Add these values to the selectoption list.
for (Schema.PicklistEntry a : values)
{
options.add(new SelectOption(a.getLabel(), a.getValue()));
}
return options;
}

private static testMethod void testVf()
{
// The standard Account object’s standard Industry field is a picklist.
// Required fields or validation rules on the Account object will cause
// this to fail.
list testOptions =
getPicklistValues(new Account(Name = ‘Test’), ‘Industry’);
system.assert(testOptions.size() > 0);
}

// ==============================================================================
// STRINGS
// ==============================================================================
// Implement toString() methods for simple variables.
global static String toString(Integer val) { return val.format(); }
global static String toString(Decimal val) { return val.toPlainString(); }
global static String toString(Double val) { return val.format(); }
global static String toString(Long val) { return val.format(); }
global static String toString(Date val) { return val.format(); }
global static String toString(Date val, String fmt)
{
Datetime tmp = Datetime.newInstance(val.year(), val.month(), val.day());
return tmp.format(fmt);
}
global static String toString(Datetime val) { return val.format(); }
global static String toString(Datetime val, String fmt) { return val.format(fmt); }
global static String toString(Time val) { return String.valueOf(val); }
global static String toString(Time val, String fmt)
{
Datetime tmp = Datetime.newInstance(1970, 1, 1, val.hour(), val.minute(), val.second());
return tmp.format(fmt);
}
global static String toString(Boolean val) { if (val) return ‘true’; else return ‘false’; }

private static testMethod void testToString()
{
system.assertEquals(‘12,345’, toString(Integer.valueOf(12345)));
system.assertEquals(‘1.2345’, toString(Decimal.valueOf(‘1.2345’)));
system.assertEquals(‘1.234’, toString(Double.valueOf(‘1.2345’)));
system.assertEquals(‘1,234,567,890’, toString(Long.valueOf(‘1234567890’)));
system.assertEquals(‘1/1/1970’, toString(Date.newInstance(1970, 1, 1)));
system.assertEquals(‘January 1, 1970’,
toString(Date.newInstance(1970, 1, 1), ‘MMMM d, yyyy’));
system.assertEquals(‘January 1, 1970’,
toString(Datetime.newInstance(1970, 1, 1, 0, 0, 0), ‘MMMM d, yyyy’));
system.assertEquals(‘1/1/1970 12:00 AM’,
toString(Datetime.newInstance(1970, 1, 1, 0, 0, 0)));
system.assertEquals(’00:00:00.000Z’, toString(Time.newInstance(0, 0, 0, 0)));
system.assertEquals(’12:00′, toString(Time.newInstance(0, 0, 0, 0), ‘hh:mm’));
system.assertEquals(‘true’, toString(true));
system.assertEquals(‘false’, toString(false));
}

global static final String RANDOM_CHARS =
‘ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789’;
global static final String ALPHA_CHARS =
‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’;
global static final String PUNCTUATION_CHARS =
‘`~!@#$%^&*()_+-={}[]:”;\'<>?,\\./\”‘;
global static final String RANDOM_ALPHA = ’25’;
global static final String RANDOM_ALL = ’35’;

// Generate random strings.
global static String getRandomAlphaString(Integer len)
{ return getRandomString(len, RANDOM_ALPHA); }
global static String getRandomString(Integer len)
{ return getRandomString(len, RANDOM_ALL); }
global static String getRandomString(Integer len, String mode)
{
String retVal = ”;
if (len != null && len >= 1)
{
Integer chars = 0;
Integer random;
do
{
random = Math.round(Math.random() * Integer.valueOf(mode));
retVal += RANDOM_CHARS.substring(random, random + 1);
chars++;
} while (chars < len);
}
return retVal;
}

// Is this string alpha?
global static Boolean isAlpha(String val)
{
Integer len = val.length();
for (Integer i = 0; i < len; i++)
{
if (!ALPHA_CHARS.contains(val.substring(i, i + 1)))
{
return false;
}
}
return true;
}

// Is this string alphanumeric?
global static Boolean isAlphaNumeric(String val)
{
Integer len = val.length();
for (Integer i = 0; i < len; i++)
{
if (!RANDOM_CHARS.contains(val.substring(i, i + 1)))
{
return false;
}
}
return true;
}

// Does this string contain punctuation?
global static Boolean hasPunctuation(String val)
{
Integer len = val.length();
for (Integer i = 0; i < len; i++)
{
if (PUNCTUATION_CHARS.contains(val.substring(i, i + 1)))
{
return true;
}
}
return false;
}

// Is this string null? empty?
global static Boolean isNull(String val)
{
return (val == null ? true : false);
}
global static Boolean isBlank(String val)
{
return ((val == null || val == ”) ? true : false);
}

// Does this string have whitespace within it?
global static Boolean hasWhitespace(String val)
{
return (val.contains(‘ ‘) ||
val.contains(‘\n’) ||
val.contains(‘\t’) ||
val.contains(‘\f’) ||
val.contains(‘\r’));
}
global static Boolean hasCrlf(String val)
{
return (val.contains(‘\n’) || val.contains(‘\r’));
}

// Create shortcuts for substring().
global static String left(String val, Integer len)
{
String retVal = val;
if (len <= val.length())
{
retVal = val.substring(0, len);
}
return retVal;
}
global static String right(String val, Integer len)
{
String retVal = ”;
retVal = val.substring(val.length() – len);
return retVal;
}

// Remove the final delimiter from a string.
global static String stripFinal(String val, String delim)
{
String retVal = ”;
if (val.endsWith(delim))
{
retVal = left(val, val.length() – delim.length());
}
return retVal;
}

// Join together an array of Strings delimited as specified.
global static String joinList(String[] lst, String delim)
{
String retVal = ”;
Boolean firstOne = true;
for (String s : lst)
{
if (s != null)
{
if (firstOne)
{
firstOne = false;
}
else
{
retVal += delim;
}
retVal += s;
}
}
return retVal;
}

private static testMethod void testStrings()
{
system.assertEquals(true, isAlpha(‘ABC’));
system.assertEquals(false, isAlpha(‘___’));
system.assertEquals(true, isAlphaNumeric(‘ABC123’));
system.assertEquals(false, isAlphaNumeric(‘______’));
system.assertEquals(true, isNull(null));
system.assertEquals(false, isNull(”));
system.assertEquals(true, isBlank(”));
system.assertEquals(false, isBlank(‘_’));
system.assertEquals(true, hasWhitespace(‘ ‘));
system.assertEquals(false, hasWhitespace(‘_’));
system.assertEquals(true, hasCrlf(‘\n’));
system.assertEquals(false, hasCrlf(‘_’));
system.assertEquals(true, hasPunctuation(‘#$%’));
system.assertEquals(false, hasPunctuation(‘ABC’));
system.assertEquals(6, getRandomAlphaString(6).length());
system.assertEquals(6, getRandomString(6).length());
system.assertEquals(6, getRandomString(6, RANDOM_ALPHA).length());
system.assertEquals(‘ABC’, left(‘ABCDEF’, 3));
system.assertEquals(‘DEF’, right(‘ABCDEF’, 3));
system.assertEquals(‘1,2,3’, stripFinal(‘1,2,3,’, ‘,’));
String[] lst = new String[] { ‘1’, ‘2’, ‘3’ };
system.assertEquals(‘1,2,3’, joinList(lst, ‘,’));
}
// ==============================================================================
// DATES, TIMES & DATETIMES
// ==============================================================================

// Get date portion of datetime.
global static Date getDate(Datetime dt)
{
return Date.newInstance(dt.year(), dt.month(), dt.day());
}

// Get datetime from date.
global static Datetime getDatetime(Date d)
{
return Datetime.newInstance(d, Time.newInstance(0, 0, 0, 0));
}

// Get the date of the end of the month.
// toStartOfMonth() gives us the beginning of the month.
global static Date getEndofMonth()
{
return system.today().addMonths(1).toStartOfMonth().addDays(-1);
}
global static Date getEndofMonth(Date d)
{
return d.addMonths(1).toStartOfMonth().addDays(-1);
}

// Get the first day of the next month as a date.
global static Date getBeginNextMonth()
{
return system.today().addMonths(1).toStartofMonth();
}
global static Date getBeginNextMonth(Date d)
{
return d.addMonths(1).toStartofMonth();
}

// Get the date of the end of the week.
// toStartOfWeek() gives us the beginning of the week.
global static Date getEndofWeek()
{
return system.today().addDays(7).toStartOfWeek().addDays(-1);
}
global static Date getEndofWeek(Date d)
{
return d.addDays(7).toStartOfWeek().addDays(-1);
}

// Given a time string in the format HH:MM, in 24-hour format,
// return that as a time.
global static Time getTime(String s)
{
if (s.length() == 5)
{
Integer hours = Integer.valueOf(s.substring(0, 2));
Integer minutes = Integer.valueOf(s.substring(3, 5));
Time t = Time.newInstance(hours, minutes, 0, 0);
return t;
}
return null;
}

// Given a datetime, return the time component.
global static Time getTime(Datetime dt)
{
String t = dt.format(‘hh:mm’);
return getTime(t);
}

// Given a time component, return that as a time string.
global static String getTime(Time t)
{
String retval = ”;
Integer hours = t.hour();
Integer minutes = t.minute();
String h = ‘0’ + hours.format();
String m = ‘0’ + minutes.format();
retVal = (h.substring(h.length()-2, h.length()) +
‘:’ + m.substring(m.length()-2, m.length())).substring(0, 5);
return retVal;
}

// Given two times or datetimes, determine the number of seconds between them.
global static Long getSecondsBetween(Time t1, Time t2)
{
Datetime dt1 = Datetime.newInstance(system.today(), t1);
Datetime dt2 = Datetime.newInstance(system.today(), t2);
Long secondsBetween = dt2.getTime() – dt1.getTime();
return Math.abs(secondsBetween / 1000L);
}
global static Long getSecondsBetween(Datetime dt1, Datetime dt2)
{
Long secondsBetween = dt2.getTime() – dt1.getTime();
return Math.abs(secondsBetween / 1000L);
}

// Given the number of seconds between two date/times,
// calculate the number of minutes. Fractional minutes are dropped.
global static Long getMinutesBetween(Datetime dt1, Datetime dt2)
{
return (getSecondsBetween(dt1, dt2) / 60L);
}

// Calculate the number of hours. Fractional hours are dropped.
global static Long getHoursBetween(Datetime dt1, Datetime dt2)
{
return (getSecondsBetween(dt1, dt2) / 3600L);
}

// Adjust this list to match your locale and business rules.
global static list dows =
new String[]{ ‘Su’, ‘Mo’, ‘Tu’, ‘We’, ‘Th’, ‘Fr’, ‘Sa’ };

global static Integer getDow(Date d)
{
Integer dow = -1;
if (d != null)
{
String day = Datetime.newInstance(d,
Time.newInstance(0, 0, 0, 0)).format(‘E’).substring(0, 2);
for (Integer i = 0; i < 7; i++)
{
if (day == dows[i])
{
dow = i;
break;
}
}
}
return dow;
}

// Get the name of the day of the week.
global static String getDowName(Date d)
{
return Datetime.newInstance(d,
Time.newInstance(0, 0, 0, 0)).format(‘EEEE’);
}

private static testMethod void testDates()
{
Date testDate = Date.newInstance(1970, 1, 1);
Datetime testDatetime = Datetime.newInstance(1970, 1, 1, 0, 0, 0);
Datetime testDatetime2 = testDatetime.addHours(1);
Time testTime = Time.newInstance(0, 0, 0, 0);
Time testTime2 = testTime.addHours(1);
system.assertEquals(testDate, getDate(testDatetime));
system.assertEquals(testDatetime, getDatetime(testDate));
system.assertEquals(testDate.addMonths(1).toStartOfMonth().addDays(-1),
getEndofMonth(testDate));
system.assertEquals(system.today().addMonths(1).toStartOfMonth().addDays(-1),
getEndofMonth());
system.assertEquals(testDate.addMonths(1).toStartOfMonth(),
getBeginNextMonth(testDate));
system.assertEquals(system.today().addMonths(1).toStartOfMonth(),
getBeginNextMonth());
system.assertEquals(testDate.addDays(7).toStartOfWeek().addDays(-1),
getEndofWeek(testDate));
system.assertEquals(system.today().addDays(7).toStartOfWeek().addDays(-1),
getEndofWeek());
system.assertEquals(’00:00′, getTime(testTime));
system.assertEquals(null, getTime(‘X’));
system.assertEquals(testTime, getTime(’00:00′));
system.assertEquals(’12:00′, getTime(getTime(testDatetime)));
system.assertEquals(3600, getSecondsBetween(testTime, testTime2));
system.assertEquals(3600, getSecondsBetween(testDatetime, testDatetime2));
system.assertEquals(60, getMinutesBetween(testDatetime, testDatetime2));
system.assertEquals(1, getHoursBetween(testDatetime, testDatetime2));
system.assertEquals(4, getDow(testDate));
// This is locale-specific, obviously.
system.assertEquals(‘Thursday’, getDowName(testDate));
}

// ==============================================================================
// ERROR-HANDLING
// ==============================================================================

// Declare custom exceptions.
global class customException extends Exception {}
global class badArgumentException extends Exception {}
global class nullArgumentException extends Exception {}

// If you have a team of developers working on a project,
// you may have to wade through an ocean of debug messages.
// This handy method lets you find your debug messages quickly.
global static String showDebug(String lbl, String dbg)
{
String s = ‘FROM ‘ + userInfo.getUserName() + ‘: ‘ + lbl + ‘=’ + dbg;
system.debug(s);
return s;
}

// As a matter of course, we automatically write all of these
// messages to the debug log.
global static String showConfirm(String conf)
{
showDebug(‘CONFIRM’, conf);
ApexPages.Message msg =
new ApexPages.Message(ApexPages.Severity.Confirm, conf);
ApexPages.addMessage(msg);
return conf;
}

global static String showInfo(String info)
{
showDebug(‘INFO’, info);
ApexPages.Message msg =
new ApexPages.Message(ApexPages.Severity.Info, info);
ApexPages.addMessage(msg);
return info;
}

global static String showWarning(String warn)
{
showDebug(‘WARNING’, warn);
ApexPages.Message msg =
new ApexPages.Message(ApexPages.Severity.Warning, warn);
ApexPages.addMessage(msg);
return warn;
}

global static String showError(String err)
{
showDebug(‘ERROR’, err);
ApexPages.Message msg =
new ApexPages.Message(ApexPages.Severity.Error, err);
ApexPages.addMessage(msg);
return err;
}

// Strip the error message and line number from the exception and
// show it to the user. This is an easy way to handle unhandled exceptions.
global static String showError(Exception ex)
{
return showError(ex, ”);
}
global static String showError(Exception ex, String err)
{
String errMsg =
(err == null || err == ” ? ” : err + ‘: ‘) +
ex.getMessage() + ‘ at line ‘ +
ex.getLineNumber().format();
showDebug(‘FATAL’, errMsg);
ApexPages.Message msg =
new ApexPages.Message(ApexPages.Severity.Error, errMsg);
ApexPages.addMessage(msg);
return errMsg;
}

private static testMethod void testDebug()
{
system.assertEquals(‘FROM ‘ + userInfo.getUserName() + ‘: var=val’,
showDebug(‘var’, ‘val’));
system.assertEquals(‘Confirm’, showInfo(‘Confirm’));
system.assertEquals(‘Info’, showInfo(‘Info’));
system.assertEquals(‘Warning’, showWarning(‘Warning’));
system.assertEquals(‘Error’, showError(‘Error’));
system.assertEquals(‘Error at line’,
showError(new customException(‘Error’)).substring(0, 14).trim());
system.assertEquals(‘Test: Error at line’,
showError(new customException(‘Error’), ‘Test’).substring(0, 19).trim());
}

// ==============================================================================
// SYSTEM & METADATA
// ==============================================================================

// What edition is this?
global static String getOrgEdition()
{
list orgs =
[SELECT Id, OrganizationType FROM Organization LIMIT 1];
// This HAS to exist.
return orgs[0].OrganizationType;
}

// Returns a dynamic SOQL statement for any object,
// including only creatable fields. Used for cloning.
global static String getCreateableFieldsSoql(String obj)
{
return getCreateableFieldsSoql(obj, ”);
}
global static String getCreateableFieldsSoql(String obj, String whereClause)
{
String sql = ”;
String fieldString = ”;
list fieldList = new list();
// Get a map of field names for this object type.
Map<string, schema.sobjectfield=””> fieldMap =
Schema.getGlobalDescribe().get(obj.toLowerCase()).getDescribe().fields.getMap();
if (fieldMap != null)
{
// Loop through all fields.
for (Schema.SObjectField f : fieldMap.values())
{
// Describe each field.
Schema.DescribeFieldResult fd = f.getDescribe();
// Is this field is createable? If so, we can clone it.
if (fd.isCreateable())
{
// This is the API name.
fieldList.add(fd.getName());
}
}
}
// Sort and assemble field list.
if (!fieldList.isEmpty())
{
fieldList.sort();
for (string s : fieldList)
{
fieldString += s + ‘, ‘;
}
}
// Strip terminal comma.
if (fieldString.endsWith(‘, ‘))
fieldString = fieldString.substring(0, fieldString.lastIndexOf(‘,’));
// Assemble SQL statement.
sql = ‘SELECT ‘ + fieldString + ‘ FROM ‘ + obj;
// Append WHERE clause if present; if ORDER BY or LIMIT are needed,
// append them to WHERE clause when calling this method.
if (whereClause != null && whereClause != ”) sql += ‘ WHERE ‘ + whereClause;
return sql;
}

// Returns a dynamic SOQL statement for any object,
// including all accessible fields: SELECT * FROM [object].
global static String getAccessibleFieldsSoql(String obj)
{ return getAccessibleFieldsSoql(obj, ”); }
global static String getAccessibleFieldsSoql(String obj, String whereClause)
{
String sql = ”;
String fieldString = ”;
list fieldList = new list();
// Get a map of field names for this object type.
Map<string, schema.sobjectfield=””> fieldMap =
Schema.getGlobalDescribe().get(obj.toLowerCase()).getDescribe().fields.getMap();
if (fieldMap != null)
{
// Loop through all fields.
for (Schema.SObjectField f : fieldMap.values())
{
// Describe each field.
Schema.DescribeFieldResult fd = f.getDescribe();
// Is this field is queryable? If so, we can query it.
if (fd.isAccessible())
{
// This is the API name.
fieldList.add(fd.getName());
}
}
}
// Sort and assemble field list.
if (!fieldList.isEmpty())
{
fieldList.sort();
for (string s : fieldList)
{
fieldString += s + ‘, ‘;
}
}
// Strip terminal comma.
if (fieldString.endsWith(‘, ‘))
fieldString = fieldString.substring(0, fieldString.lastIndexOf(‘,’));
// Assemble SQL statement.
sql = ‘SELECT ‘ + fieldString + ‘ FROM ‘ + obj;
// Append WHERE clause if present; if ORDER BY or LIMIT are needed,
// append them to WHERE clause when calling this method.
if (whereClause != null && whereClause != ”) sql += ‘ WHERE ‘ + whereClause;
return sql;
}

global static final String API_LABEL = ‘API Requests, Last 24 Hours’;

// Get maximum number of API requests available.
global static Integer getApiMax()
{
// Get the current organization ID.
Organization org = [SELECT Id FROM Organization LIMIT 1];
// Get the actual contents of the page associated with that organization ID.
PageReference pr = new PageReference(‘/’ + String.valueOf(org.Id));
pr.setRedirect(false);
String result = ”;
// You can’t use getContent() in a test method.
if (Test.isRunningTest())
{
result = Blob.valueOf(API_LABEL + ‘ 12,345 (45,678 max)’).toString();
}
else
{
result = pr.getContent().toString();
}
if (result != null)
{
// Find the label for API requests.
Integer startIndex = result.indexOf(API_LABEL, 1) + (Test.isRunningTest() ? 29 : 52);
startIndex = result.IndexOf(‘(‘, startIndex) + 1;
// Find the first space afterward; this is the max API requests.
Integer endIndex = result.indexOf(‘ ‘, startIndex);
result = result.substring(startIndex, endIndex);
// Clean up the result.
result = result.replaceAll(‘\\(‘, ”);
result = result.replaceAll(‘ ‘, ”);
result = result.replaceAll(‘,’, ”);
}
return Integer.valueOf(result);
}

// Get current number of API requests used right now.
global static Integer getApiCurrent()
{
// Get the current organization ID.
Organization org = [SELECT Id FROM Organization LIMIT 1];
// Get the actual contents of the page associated with that organization ID.
PageReference pr = new PageReference(‘/’ + String.valueOf(org.Id));
pr.setRedirect(false);
String result = ”;
if (Test.isRunningTest())
{
result = Blob.valueOf(API_LABEL + ‘ 12,345 (45,678 max)’).toString();
}
else
{
result = pr.getContent().toString();
}
if (result != null)
{
// Find the label for API requests.
Integer startIndex = result.indexOf(API_LABEL, 1) + (Test.isRunningTest() ? 29 : 52);
// Find the first space afterward; this is the current API requests.
Integer endIndex = result.indexOf(‘ ‘, startIndex);
result = result.substring(startIndex, endIndex);
// Clean up the result.
result = result.replaceAll(‘ ‘, ”);
result = result.replaceAll(‘,’, ”);
}
return Integer.valueOf(result);
}

// Get available number of API requests available right now.
global static Integer getApiLeft()
{
return getApiMax() – getApiCurrent();
}

// Is this a sandbox org?
global static Boolean isSandbox()
{
// By offering a polymorphic variation on this,
// we can improve our test coverage.
return isSandbox(URL.getSalesforceBaseUrl().getHost());
}
global static Boolean isSandbox(String host)
{
// Get the subdomain.
String server = host.substring(0, host.indexOf(‘.’));
// tapp0 is a unique “non-cs” server so check it now.
if (server == ‘tapp0’) return true;
// If server is ‘cs’ followed by a number it’s a sandbox.
if (server.length() > 2)
{
if (server.substring(0, 2) == ‘cs’)
{
return true;
}
}
// If we made it here it’s a production box.
return false;
}

private static testMethod void testSystem()
{
system.assert(getOrgEdition() != null);
system.assert(getCreateableFieldsSoql(‘Account’) != null);
system.assert(getCreateableFieldsSoql(‘Account’, ‘LIMIT 1’) != null);
system.assert(getAccessibleFieldsSoql(‘Account’) != null);
system.assert(getAccessibleFieldsSoql(‘Account’, ‘LIMIT 1’) != null);
system.assertEquals(45678, getApiMax());
system.assertEquals(12345, getApiCurrent());
system.assertEquals(33333, getApiLeft());
system.assert(getOrgEdition() != null);
system.assertEquals(true, isSandbox(‘tapp0.salesforce.com’));
system.assertEquals(true, isSandbox(‘cs1.salesforce.com’));
system.assertEquals(false, isSandbox(‘na1.salesforce.com’));
}
}

Print Friendly, PDF & Email
This entry was posted in Development. Bookmark the permalink.