[SalesForce] Use one VisualforcePage for multiple overrides

I'm using a VF page as a "dispatcher" to display different pages based on an object recordtype.

<!-- OverrideCaseView
     If Case is a XXXX, show in the XXXXX user interface
     Otherwise, show the normal Case page.
-->
<apex:page standardController="Case"
    action="{!IF(case.RecordType.DeveloperName='XXXXXXXXX',
                 URLFOR($Page.XXXXXXOverview, null, [id=case.Id], true),
              URLFOR($Action.Case.View, case.Id, null, true))}">
    <apex:outputPanel style="display:none;" >
        {!case.RecordType.DeveloperName}
    </apex:outputPanel>
</apex:page>

Up until now, I've just been doing View overrides, but I'm adding some edit overrides as well. When they're complex, it makes sense to have a separate dispatcher page, and I'm trying to figure out if I could re-use the same page for simple cases.

When writing a VF page to be used as a button/action override, is there any way to tell which action you're overriding? Is this information included in any parameters or global variables?

Best Answer

Visualforce Pages and Action Overrides.

Currently there is no context other than that passed in the standard controller given to you by the platform. Which really just gives you the SObject and not the action invoked apone it. However this allows your controller code to be generic at least. Allowing you to reuse a controller between different pages...

You can only associate pages to Action Functions that use standard controllers and hence the object needs to be explicitly stated on the page, preventing the pages from being reused between other objects. Context wise, you can determine your current page however. So it then becomes a question of how light you can make your Action Override pages....

Dispatch Suggestion "Using very small pages for mulitple overrides".

Create an extension controller, MyDispatchController, with a 'dispatch' method on it (returning PageReference). Then create a VF page for each action you want to override and configure the Action Override to each. As a minimum it would look like this for a Test object...

Dispatch Action Pages and Controller:

Create for example, testdispatchedit.page, testdispatchnew.page and testdispatchview.page each looking like the following...

<apex:page standardController="Test__c" extensions="MyDispatchController" action="{!dispatch}"/>

Then in the 'dispatch' method of the controller put your object and/or action dispatch logic...

public with sharing class MyDispatchController 
{
    public MyDispatchController(ApexPages.StandardController stdController) { }

    public PageReference dispatch()
    {
        if(ApexPages.currentPage().getUrl().contains('view'))
            // Some disaptching logic resulting in a PageReference 
            //   (could also reference standardController.getRecord() for object type)...
            return Page.testviewa;
        else if(ApexPages.currentPage().getUrl().contains('edit'))
            // Some disaptching logic resulting in a PageReference 
            //   (could also reference standardController.getRecord() for object type)...
            return Page.testedita;
        else if(ApexPages.currentPage().getUrl().contains('new'))
            // Some disaptching logic resulting in a PageReference 
            //   (could also reference standardController.getRecord() for object type)...
            return Page.testnewa;
        return null;    
    }
}

For the pages that you dispatch to, define these as follows...

testedita.page:

<apex:page standardController="Test__c" extensions="MyDispatchController,TestEditAController">
    Edit Page A
</apex:page>

testnewa.page:

<apex:page standardController="Test__c" extensions="MyDispatchController,TestNewAController">
    New Page A
</apex:page>

testviewa.page:

<apex:page standardController="Test__c" extensions="MyDispatchController,TestViewAController">
    View Page A
</apex:page>

VF Bindings and Standard Controller Record: Note that the standard controller record is initialised with the fields as per those referenced on the disapatch page. Which of course does not reference any fields. This means that standardController.getRecord() will really only have the Id field populated. You could resolve this by adding some bindings to the dispatch page (these won't be displayed), say for some common fields all your dispatch to pages need. So be aware that the final controllers will likely have to query themselves for the information they need and expose this to the page themselves.

Summary: This solution leverages a feature of Visualforce that allows you to share controller instances between pages. So long as they share the same controllers. This allows your final pages to also see the same instance of the MyDispatchController, should you want to store anything in that during the dispatch, that you want to reference.

Hope this helps!