Using Dynamic References with Custom Objects and Packages

Package developers can use dynamic Visualforce binding to list only the fields a user can access. This situation might occur when you’re developing a managed package with a Visualforce page that displays fields on an object. Since the package developer doesn’t know which fields a subscriber can access, he or she can define a dynamic page that renders differently for each subscriber. The following example uses a custom object packaged with a page layout using a Visualforce page to demonstrate how different subscribing users view the same page.

  1. Create a custom object called Book with the following fields and data types:
    • Title: Text(255)
    • Author: Text(255)
    • ISBN: Text(13)
    • Price: Currency(4, 2)
    • Publisher: Text(255)
    By default creating a new custom object will create a layout for that object. Call the layout Book Layout.
  2. Modify the layout so it displays the custom fields above and removes the standard fields such as Created By, Last Modified By, Owner, and Name.
  3. Create a new custom object tab. Set the object to Book, and the tab style to Books.
  4. Switch to the Book tab and create a few Book objects. For this tutorial, the data inside the fields doesn’t actually matter.
  5. Create a controller extension called bookExtension with the following code:
    public with sharing class bookExtension {
        private ApexPages.StandardController controller;
    
        private Set<String> bookFields = new Set<String>();
        
        public bookExtension (ApexPages.StandardController controller) {
            this.controller = controller;
            Map<String, Schema.SobjectField> fields = 
            Schema.SobjectType.Book__c.fields.getMap();
    
            for (String s : fields.keySet()) {
            // Only include accessible fields 
                if (fields.get(s).getDescribe().isAccessible() && 
                    fields.get(s).getDescribe().isCustom()) {
                        bookFields.add(s);
                }
            }
        }
        
        public  List<String> availableFields {
            get {
                controller.reset(); 
                controller.addFields(new List<String>(bookFields));
                    return new List<String>(bookFields);
            }
        }
    }
  6. Create a Visualforce page called booksView that uses the controller extension to show the values of the Book object:
    <apex:page standardController="Book__c" extensions="bookExtension" > 
    
        <br/>
        <apex:pageBlock title="{!Book__c.Name}">
            <apex:repeat value="{!availableFields}" var="field">
    
                <h2><apex:outputText 
                     value="{!$ObjectType['Book__c'].Fields[field].Label}"/></h2>
                <br/>
                <apex:outputText value="{!Book__c[field]}" /><br/><br/>
    
            </apex:repeat>
        </apex:pageBlock>
    
    </apex:page>
    
  7. Since the controller extension is going to be packaged, you’ll need to create a test for the Apex class. Create an Apex class called bookExtensionTest with this basic code to get you started:
    public with sharing class bookExtension {
    
        private ApexPages.StandardController controller;
        private Set<String> bookFields = new Set<String>();
        
        public bookExtension (ApexPages.StandardController controller) {
            this.controller = controller;
            Map<String, Schema.SobjectField> fields = 
                Schema.SobjectType.Book__c.fields.getMap();
    
            for (String s : fields.keySet()) {
                // Only include accessible fields 
                if (fields.get(s).getDescribe().isAccessible() && 
                    fields.get(s).getDescribe().isCustom()) {
                        bookFields.add(s);
                }
            }
            controller.addFields(new List<String>(bookFields));
        }
        
        public  List<String> availableFields {
            get {
                controller.reset(); 
                controller.addFields(new List<String>(bookFields));
                return new List<String>(bookFields);
            }
        }
    }
    Note

    Note

    This Apex test is only meant to be a sample. When creating tests that are included into packages, validate all behavior, including positive and negative results.

  8. Create a package called bookBundle, and add the custom object, the Visualforce page, and the bookExtensionTest Apex class. The other referenced elements are included automatically.
  9. Install the bookBundle package into a subscriber organization.
  10. After the package is installed, from the object management settings for books, add a new field called Rating.
  11. Create a new Book object. Again, the values for the record don’t actually matter.
  12. Navigate to the booksView page with the package namespace and book ID appended to the URL. For example, if GBOOK is the namespace, and a00D0000008e7t4 is the book ID, the resulting URL should be https://Salesforce_instance/apex/GBOOK__booksView?id=001D000000CDt53.

When the page is viewed from the subscribing organization, it should include all the packaged Book fields, plus the newly created Rating field. Different users and organizations can continue to add whatever fields they want, and the dynamic Visualforce page will adapt and show as appropriate.

Previous
Next