Wednesday 13 June 2012

Data encapsulation in Visualforce page and controller

Generally visualforce page in salesforce usese page variables defined as public in controller which can be accessed directly which is not a good Object Oriented design. In this article i will show how to convert a normal visulaforce page which uses public variables to a much Object Oriented visualforce page which will use data encapsulation techinque to hide data by making it private.

A typical Visualforce page and controller looks like below :

<apex:page controller="TestController" >
<apex:form id="testForm">
<apex:pageBlock id="TestBlock">
  <apex:pageBlockSection title="Submitted Data"  rendered="{!isOutputRendered}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:outputText value="{!name}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:outputText value="{!product}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:outputText value="{!productManager}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:outputText value="{!description}"></apex:outputText>
   </apex:pageBlockSectionItem>
  <center>
<apex:commandButton value="Re-Enter Data" action="{!reEnterData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>
 <apex:pageBlockSection title="Enter Data" rendered="{!NOT(isOutputRendered)}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:inputText value="{!name}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:inputText value="{!product}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:inputText value="{!productManager}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:inputText value="{!description}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <center>
   <apex:commandButton value="Submit Data" action="{!submitData}" reRender="testForm"/>
   </center>
 </apex:pageBlockSection>

 </apex:pageBlock>
 </apex:form>
 </apex:page>

Controller for above page:

public class TestController
{
 public Boolean isOutputRendered{get;set;}
 public String description{get;set;}
 public String name{get;set;}
 public String product{get;set;}
 public String productManager{get;set;}

public TestController ()
{
  isOutputRendered=false;
}
public PageReference submitData()
{
 isOutputRendered=true;
 return null;
}
public PageReference reEnterData()
{
  isOutputRendered=false;
 return null;
}
}

Above page is a simple which takes user inputs and displays it back to user. Her if you observe all the page variables are defined as public which is not a good Object Oriented design.

Below is the transformed version of above page where page vairbales will be private and provide data encapsulation.

<apex:page controller="TestController" >
<apex:form id="testForm">
<apex:pageBlock id="TestBlock">
  <apex:pageBlockSection title="Submitted Data"  rendered="{!dataClass.isOutputRendered}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:outputText value="{!dataClass.name}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:outputText value="{!dataClass.product}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:outputText value="{!dataClass.productManager}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:outputText value="{!dataClass.description}"></apex:outputText>
   </apex:pageBlockSectionItem>
  <center>
<apex:commandButton value="Re-Enter Data" action="{!reEnterData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>
 <apex:pageBlockSection title="Enter Data" rendered="{!NOT(dataClass.isOutputRendered)}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:inputText value="{!dataClass.Name}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:inputText value="{!dataClass.product}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:inputText value="{!dataClass.productManager}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:inputText value="{!dataClass.description}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <center>
<apex:commandButton value="Submit Data" action="{!submitData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>

 </apex:pageBlock>
 </apex:form>
 </apex:page>

TestController :

public class TestController {
 private TestDataClass dataClass=null;
 public TestDataClass getDataClass()
{
 return this.dataClass;
}
public TestController ()
{
 dataClass=new TestDataClass();
 dataClass.setIsOutputRendered(false);
}
public PageReference submitData()
{
 dataClass.setIsOutputRendered(true);
 return null;
}
public PageReference reEnterData()
{
 dataClass.setIsOutputRendered(false);
 return null;
}
}

If you would have observed in controller i have created a private variable 'dataClass' of  'TestDataClass'. TestDataClass is the class which will contain all the varibles which will be used in page.

TestDataClass:

public class TestDataClass
{
 private Boolean isOutputRendered;
 private String description;
 private String name;
 private String product;
 private String productManager;
 public Boolean getIsOutputRendered() {
  return isOutputRendered;
 }
 public void setIsOutputRendered(Boolean isOutputRendered) {
  this.isOutputRendered = isOutputRendered;
 }
 public String getDescription() {
  return description;
 }
 public void setDescription(String description) {
  this.description = description;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getProduct() {
  return product;
 }
 public void setProduct(String product) {
  this.product = product;
 }
 public String getProductManager() {
  return productManager;
 }
 public void setProductManager(String productManager) {
  this.productManager = productManager;
 }
}


Above approach encapsulates data and also separates data and logic.

All code above is tried and tested with salesforcec summer'12 release. Let me know if you are having any issue implementing above design.

Sunday 10 June 2012

Writing trigger - A Clean Approach

What is a best way to write a trigger? Different people will have different opinions and different answers for this question. Here is one clean approach to write a trigger which will be following below few guidelines:
1. There should be only one trigger on one object.
2. There  should be only one loop per event. For Ex: before Insert, before Update etc.

Here is the sample trigger code which implements above guidelines.

Trigger testObjectTrigger on TestObject__c(before Insert,before update, after insert, after update)
{
  List<TestObject__c> testObjectListBeforeInsert=new List<TestObject__c>();
  List<TestObject__c> testObjectListBeforeUpdate=new List<TestObject__c>();
  List<TestObject__c> testObjectListAfterInsert=new List<TestObject__c>();
  List<TestObject__c> testObjectListAfterUpdate=new List<TestObject__c>();

 
  if(Trigger.isBefore)
 {
    if(Trigger.isInsert)
   {
     for(TestObject__c toc: trigger.New)
     {
       Boolean isBeforeInsertCondition=<Your condition >;
       if(isBeforeInsertCondition)
       {
        testObjectListBeforeInsert.add(toc);
        }
     }   
    }
    if(Trigger.isUpdate)
    {
      for(TestObject__c toc: trigger.New)
     {
       Boolean isBeforeUpdateCondition=<Your condition >;
       if(isBeforeUpdateCondition)
       {
        testObjectListBeforeUpdate.add(toc);
        }
      }   
    }
 }
 if(Trigger.isAfter)
 {
   if(Trigger.isInsert)
   {
     for(TestObject__c toc: trigger.New)
     {
       Boolean isAfterInsertCondition=<Your condition >;
       if(isAfterInsertCondition)
       {
        testObjectListAfterInsert.add(toc);
        }
     }   
   }

  if(Trigger.isUpdate)
    {
      for(TestObject__c toc: trigger.New)
     {
       Boolean isAfterUpdateCondition=<Your condition >;
       if(isAfterUpdateCondition)
       {
        testObjectListAfterUpdate.add(toc);
        }
      }   
    }
 }
 if(testObjectListBeforeInsert.size()>0)
 {
   ............
   Your code to perform operation or call to other class method to perform operation.
   .............
 }
 if(testObjectListBeforeUpdate.size()>0)
 {
   ............
   Your code to perform operation or call to other class method to perform operation.
   .............
 }
 if(testObjectListAfterInsert.size()>0)
 {
   ............
   Your code to perform operation or call to other class method to perform operation.
   .............
 }
 if(testObjectListAfterUpdate.size()>0)
 {
   ............
   Your code to perform operation or call to other class method to perform operation.
   .............
 }

}
In above example i have only taken insert and update operation but above code can be extended to other operations also like delete,undelete etc.

Single controller for Multiple Visualforce pages

In salesforce we generally go with one visualforce page and one custom controller. Here i have come up with a solution where you can use same controller class for multiple pages. Below are the details of it:

1. Create a generic controller which will idetify which will identify the page which is currently being accessed.

public virtual class GenericControllerClass {
private String pageName;

public String getPageName(String url)
    {
     pageName='';
     if(url.indexOf('/apex/') != -1)
     {
      if(url.indexOf('?') != -1 )
      {
        pageName=url.subString(url.indexOf('/apex/')+6,url.indexOf('?'));
      }
      else
      {
        pageName=url.subString(url.indexOf('/apex/')+6);
      }
     }
     return pageName;
    }
}

2. Now assume you have three visuaforcePages page1,page2,page3.
page1:
<apex:page controller="SingleControllerClass">
.......
<your code here>
.......
</apex:page>

page 2:

<apex:page controller="SingleControllerClass">
.......
<your code here>
.......
</apex:page>

page 3:

<apex:page controller="SingleControllerClass">
.......
<your code here>
.......
</apex:page>


3. Now create controller class "SingleControllerClass" for above pages:

public class SingleControllerClass extends GenericControllerClass
{
  ......
  your page variables
  ......

  public SingleControllerClass()
  {
   super();
   String pageName=getPageName(ApexPages.currentPage()..getUrl());
   if(pageName=="page1")
 {
  initPage1();
 }
 else ifpageName=="page2")
 {
  initPage2();
 }
 else if(pageName=="page3")
 {
  initPage3();
 }
  }
 
  private void initPage1()
  {
    ..................
 initialize your page1 variables here.
 .................
  }
  private void initPage2()
  {
    ..................
 initialize your page2 variables here.
 .................
  }
  private void initPage3()
  {
    ..................
 initialize your page3 variables here.
 .................
  }

}


Above mentioned three steps is a very simple process to implement. Using above solution you would be able to reuse your code efficiently and it also eliminates initialization of other page variables.