Saturday 6 October 2012

Snippet View

Something I've had kicking around in my toolbox for a while now is a Snippet View page - this is a Visualforce page that provides headline information on objects that haven't been shared with the user.  This allows, for example, a user to see the name and type of an account and the user that is the owner even though the sharing rules don't give them access to the full account record.  In a private sharing model this can be a useful way to prevent duplicates - the user can see if an account already exists and request access to it without exposing sensitive information.

Back when I originally wrote this I had a set of fields that were retrieved and stored as text values in a custom class for use on the page.  One downside to this was that no specialised formatting associated with the field (if it was a rich text area, for example) applied, as they were simply text values.  With the introduction and subsequent improvements around Field Sets, I've rewritten my snippet view page and controller to deal with actual fields rather than text representations and decided it is a good candidate for a blog post.  

A further improvement is that the snippet page now handles any subject type, standard or custom, as long as there is a field set named 'Snippet' defined (or in fact a field set name 'KAB_TUTORIAL__Snippet', as my dev org has a namespace!).

The controller is pretty straightforward

public class SObjectSnippetController {
	/* The id of the object provided on the URL */
	public Id objId {get; set;}
	/* The sobject type, determined from the ID */
	public String sobjType {get; set;}
	/* The fields in the field set */
	public List<Schema.FieldSetMember> fsMems {get; set;}
	/* The sobject, with only the members of the field set populated */
	public Sobject sobj {get; set;}
	/* Error string - used if there is no Snippet field set defined */
	public String errorStr {get; set;}
	public SObjectSnippetController()
		/* extract the id from the URL */
		/* determine the sobject type and its defined field sets */
		Map<String, Schema.SObjectType> schemaMap = Schema.getGlobalDescribe();
		Map<String, Schema.FieldSet> fsMap = null;
    	for (Schema.SObjectType sot : schemaMap.values())
     		Schema.DescribeSObjectResult descRes=sot.getDescribe();
     		String kp=descRes.getKeyPrefix();
     		if (kp==((String) objId).substring(0, 3))
     			/* store the field sets for later processing */
    	if (null!=fsMap)
    		/* locate the field set for the snippet fields */
    		Schema.FieldSet fs=fsMap.get('KAB_TUTORIAL__Snippet');
    		if (null!=fs)
    			/* use dynamic SOQL to retrieve the fields in the set */
		        String query = 'SELECT ';
		        String fieldsStr='';
        		for(Schema.FieldSetMember f : fsMems)
            		fieldsStr += ', ' + f.getFieldPath();
        		query += fieldsStr.substring(2) + ' FROM ' + sobjType + ' LIMIT 1';
    	/* if we don't have an sobject, that implies the administrator hasn't defined a field set */
    	if (null==sobj)
    		errorStr='Your administrator has not defined a snippet view for this object type';

The key feature of the controller is the declaration

public class SObjectSnippetController {

As this is implicitly 'without sharing', this allows the record to be retrieved without the sharing rules being applied to the currently logged in user.

The page simply iterates the list of fields or displays the error message:

<apex:page controller="SObjectSnippetController">
  <apex:pageBlock title="Snippet View" mode="maindetail">
    <apex:pageBlockSection >
      <apex:repeat value="{!fsMems}" var="fld" rendered="{!ISBLANK(errorStr)}">
        <apex:outputField value="{!sobj[fld.fieldPath]}" />
      <apex:outputText value="{!errorStr}" rendered="{!NOT(ISBLANK(errorStr))}" />


If I attempt to access a record that isn't shared via the regular UI, I receive the expected insufficient privileges error:


If I then access the same record via the SnippetView visual force page, I can see the fields that the administrator has added to the snippet field set:



However, if I attempt to access an object that doesn't have the field set defined, I receive an error message detailing this:


No comments:

Post a Comment