Interesting title right?  What do I mean by Dynamic Programming?  By Dynamic Programming I mean using Apex to create code that can handle a variety of dynamic situations without being reprogrammed.  For example, lets say we need to export data from an Object, but we don’t know which Object…it could be Account, Contact, Opportunity, or Campaign.  So usually we’d just stick those values in a list right?  Then select the one we want.

Well lets further complicate the issue.  Let’s allow the user to select whichever Object they wish, then select the fields for that selected Object.  So far so good?

Next lets tackle the easy part.  We can use the Schema Object in Apex to get a list of all the Standard Objects (or Custom, or combination of both), and from the selected Object Type we can then query from the same Schema object all the fields. Below are a few code snippets to use in your Controller to get the Master List of Objects and how to get the fields for Each Object.



//=========================================
// Snippit - Get the Master List of Objects
//=========================================

//initialize the lists
List<SelectOption> options = new List<SelectOption>();

// Get all the Objects
for (Schema.SObjectType ObjType : Schema.getGlobalDescribe().Values())
{
    String apiName = ObjType.getDescribe().getName();
    options.add( new SelectOption(apiName, apiName) );
}  

//===============================================================
// Snippet - Code for getting the fields for each selected object
//===============================================================

List<SelectOption> listOfFields = new List<SelectOption>();

// Get the Object Type for the Selected Object
SobjectType objType = Schema.getGlobalDescribe().get(selectedObject);
			
for(Schema.SobjectField strFld: objType.getDescribe().fields.getMap().Values())
{
   if(strFld.getDescribe().isAccessible())
   {
      listOfFields.add( new SelectOption(strFld.getDescribe().getName(), strFld.getDescribe().getName()) );		 
   }
}

So let’s throw this UI together and see how she looks:

Console

I know… I didn’t publish the code for the UI or how to fill everything up and link it together…because that’s not the purpose behind this article… you can find all the code to do what I’ve outlined above in numerous places…what you don’t see much of, is the next section on dynamic development.

So now when a user selects an Object … say Campaign, and then selects the fields (or we can default it to all fields if we wish) how do we hande the fact that we don’t know ahead of time the Object (Opportunity) or how to query to make all this go.  Fortunately for us Apex has a nifty feature built into the Database Engine… query().  You can build a dynamic string and simply pass it into the Database.Query() method.



// Call this function like so:
// String qry = getSOQL('Account', listOfFiels, 0) <-- return all rows
// String qry = getSOQL('Account', listOfFiels, 20)  0)
function String getSOQL(String ObjectType, List<String> listOfFields, Integer rowLimit)
{
   String qry = 'SELECT ';
   for(String fld : listOfFields)
   {
      qry += fld + ',';
   }
   // Strip ending ","
   qry += qry.subString(0, qry.lenght() -1);
   qry += ' FROM ' + ObjectType;

   if(rowLimit > 0)
   {
      qry += ' LIMIT ' + rowLimit.format();
   }
   return( qry );
}

This solves part of the problem. But now we are faced with another problem…since we don’t know the Object Type of the resulting query how do we store the results? The answer lies in the Type.forName() method. We can actually write code which transforms the string value of the Object Type into an actual data type.

So if we take the query built in the previous function (getSOQL) we can now build a String of the return type. In order to do this we must use a List of the base SObject type. We use SObject because it can store any of the formal data type.

Continuing our example, If the Object Type is Opportunity we would create ‘List’ as the String, and then using Type.forName() cast the variable to the right type, back into a variable of type SObject.


// SObject Container List
List<SObject> sourceObjects;

// Cast sourceObjects to the formal data type 
sourceObjects = (List<SObject>)Type.forName('List<' + dynamicObject + '>').newInstance();

// Pu the query results into the list 
sourceObjects = Database.query(qry);

Utilizing this approach we now have a dynamic selection engine. You can select any Object Type, any list of fields and generate a list result set dynamically. For the final piece .. we need to generate the CSV output file. In an earlier blog (Using the Developer Console for Salesforce Administrators) I showed how to use the ContentVersion object to create the file. With a few tweaks we can make this code also generate the CSV.

A couple of assumptions have to be made since I have not built all the code… (1) a variable named “castType” stores the Selected Object Type, (2) a variable named “selectedFields” is a List of all the selected Fields.



// create the header from the List of fields
String header = String.join(selectedFields, ',') + '\n';
String csv = header;

List<SObject> resultsObjects;

// Cast resultsObjects to the formal data type 
resultsObjects = (List<SObject>)Type.forName('List<' + castType + '>').newInstance();

// Put the query results into the list 
resultsObjects = Database.query(qry);

// Loop through the results
for(integer i = 0; i < resultsObjects.size(); i++)
{
   // Must cast each row to the correct data type as well
   SObject ObjData = ((SObject)Type.forName(castType).newInstance());
   ObjData = resultsObjects[i];  

   String row;

   // Loop through all the fields for this Object			
   for(String fName : fields)
   {
      String fData = (String) ObjData.get(fName.trim());			

      if(fData.contains(','))
      {
         // Put the value in double quotes
         row += '"' + fData + '",';
      }
      else
      {
         row += fData + ',';
      }
   }
   
   // remove ending ","		
   row = row.substring(0, row.length() -1);
   csv += row + '\n';
}

// finally save this into the ContentVersion
ContentVersion file = new ContentVersion(title = 'ExportedData.csv',
                                        versionData = Blob.valueOf( csv ),
                                        review_date__c = date.today(),
                                        pathOnClient = '/ExportedData.csv');
insert file;
System.debug('Content URL : /' + file.Id);

Now you have the knowledge and the means to export any Object Type and any collection of fields to a CSV file.

[contact-form]