[SalesForce] Visualforce Page and standardController attribute in Apex Page

I am developing a Visualforce page which will be rendered when a Salesforce User arrives by clicking a specific Account.

The Apex page looks something like this:

<apex:page> 

 <c:MyComponentToBeShownOnAccountView tab="Account" />

</apex:page>

After placing this component I am able to pick this Visualforce Page from Edit Account Layout in the org and drop it as a section which I currently use for development.

But After customer installed the Managed Package my Visualforce Page doesn't appear in Visualforce Page section of the Edit Account Layout.

I did a quick fix for now by adding standardController="Account".

Now fixed page looks like:

<apex:page standardController="Account"> 

 <c:MyComponentToBeShownOnAccountView tab="Account" />

</apex:page>

My Apex Controller class is implemented as a generic class which fetches the PageReference.get('id') of the page and finds the Custom Object through SOQL. So I am not inheriting the Account Controller and handling the Account request with a separate controller.

MyCompponentToBeShownOnAccountView class looks like:

<apex:component controller="GenericObjectHandleController">
...
...
</apex:component>

I am just confused why the first code shows up on Developer but not on Enterprise, and also whether this quick fix will work across all Types of orgs.

Should I re-implement the controller by the way Salesforce recommends?

Does the problem happened due to mismatch between versions of Developer and Enterprise org?

Best Answer

You shouldn't be able to add a page to a layout without the standardController entity matching the layout's entity. It sounds like a bug in your DE org.

You should indeed use the standardController attribute on your page, and I would further recommend passing the standard controller to the component instead of grabbing the ID parameter. I use a class that looks (almost exactly) like this:

public with sharing class StandardController {
    public ApexPages.StandardController standardController { get; set; }
    public StandardController(ApexPages.StandardController standardController) {
        this.standardController = standardController;
    }
}

It's used in a page like this:

<apex:page standardController="Account" extensions="StandardController">
    <c:myComponent standardController="{!standardController}"/>
</apex:page>

Most of my components therefore use custom getter/setter methods, since it reduces my component's constructor to uselessness, but I consider it a worthy sacrifice, as I can then access the standard controller's PageReference's directly, such as cancel, view, and save.

public with sharing class myCompController {
    public ApexPages.StandardController controller {
        get; set {
            if(controller!=null) return;
            // do my component initialization here.
        }
    }
}

The standardController method works in all types of orgs. Not providing a standardController attribute is not supported and shouldn't work, so you should never rely on it working.

Related Topic