1

I have the below code which works well to clone a case record. In this scenario, we want to insert a new case and save it. But I have a new request to create sort of a quick case where we would only clone the basic information from a Case (Account, Contact, etc).

From doing research, it seems the best option would be to set a Database save point and roll back on the cancel event. Is there a better way? I have too many fields, so the url hack will not work. Also, a little confused to how to override the cancel event. I'm assuming, I would set a method to the cancel action when directed to the new record that was created. Would I also need to set the page reference to the edit page of the new record?

public class SupportCloneController {

/* Summary
   Used for Support to clone cases on button to clone all fields
   then change certain fields to defaults that we don't want values
   carried over for. Uses clone method in SupportCloneFields class 
   to copy fields. */

//Case constant
private final Case originalCase;

public SupportCloneController(ApexPages.StandardController stdController) {
    this.originalCase = (Case)stdController.getRecord();
}

List<Case>cloneList = new List<Case>();

// Code we will invoke on page load.
public PageReference supportClone() {

    String theId = ApexPages.currentPage().getParameters().get('id');

    if (theId == null) {
        // Display the Visualforce page's content if no Id is passed over
        return null;
    }

    for (Case originalCase:[SELECT Id FROM Case WHERE Id =:theId]) {
       sObject originalSObject = (sObject) originalCase;
        List<sObject> originalSObjects = new List<sObject>{originalSObject};      
            List<sObject> clonedSObjects = SupportCloneFields.cloneObjects(
                originalSobjects,
                originalSobject.getsObjectType());                                 
        Case clonedCase = (Case)clonedSObjects.get(0);

        //Update new case values as we don't want some to clone over
        cloneList.add(clonedCase);
        clonedCase.Status = 'New';
        clonedCase.Auto_Closed__c = false;
        clonedCase.Auto_Close_Reopen__c = false;
        clonedCase.Time_Spent__c = null;    
        clonedCase.do_not_email__c = false;      
        clonedCase.Count_of_Reopens__c = null;
        clonedCase.In_Progress_Delay__c = null;

        //Add original Case ID to list so we can update
        clonedCase.ParentId = originalCase.Id; 
    }

    //Save and insert cloned case
    try {       
        insert cloneList;        
    } catch(Exception e) {   
        ApexPages.addMessages(e); 
    }   

   //Redirect user to cloned case page
   Case c = cloneList.get(0);           
   PageReference pageRef = new PageReference('/' + c.Id);           
   pageRef.setRedirect(true);     
   return pageRef;       
}

}

Then for the apex page, I just call the method.

<apex:page standardController="Case"
extensions="SupportCloneController"
action="{!supportClone}"
>
    <apex:sectionHeader title="Auto-Running Apex Code"/>
    <apex:outputPanel >
        Error Message
    </apex:outputPanel>
</apex:page>
1

When I have implemented overrides of the Clone button (or created custom Clone buttons), I would not use a page action method to do the actual clone DML but instead make it work like SFDC clone:

  1. Override the Clone button with a VF page - CaseClone.page - no pageAction method but associated to a Case Controller Extension apex class
  2. SFDC will tell you you are doing a clone because of URL param clone=1
  3. In the constructor, retrieve the data from the source Case and populate an SObject that is bound to the VF page's fields. When the constructor returns, the page is populated as a normal 'new' Case page with various inputFields and outputFields per your design.
  4. Let the user change any of the defaulted, to-be-cloned fields. These changes will be posted back to the controller extension in step 5.
  5. Have the VF page include a 'Save' button bound to a 'doClone' action in the controller extension.
  6. 'doClone()' does the DML using the sobject you instantiated in step 3, and when done, redirects to the standard Case View page of the clone target Case.

Cancel works as expected, it will go back to the clone source Case standard view

Update with sample VF code ..extracted from existing system and reduced ...

<apex:page standardController="Opportunity" Extensions="OpportunityControllerExtension">

<apex:form >
  <apex:pageBlock title="Clone Information" mode="edit">
  <apex:pageMessages ></apex:pageMessages>
      <apex:pageBlockButtons >
          <apex:commandButton value="Save" action="{!doClone}"/> 
          <apex:commandButton value="Cancel" action="{!cancel}" immediate="true"/>
      </apex:pageBlockButtons>

      <apex:pageBlockSection title="Review and change as appropriate for the clone" columns="2">
        <apex:inputField value="{!clone.name}"/>
        <apex:inputField value="{!clone.amount}"/>
      </apex:pageBlockSection>
  </apex:pageBlock>
 </apex:form>
</apex:page>

Update with sample APEX code ..extracted from existing system and reduced ...

public without sharing class OpportunityControllerExtension {
  public Opportunity  clone {get; set;}

public OpportunityControllerExtension(ApexPages.StandardController stdCtlr) {
    Opportunity o               = (Opportunity) stdCtlr.getRecord();
    if (ApexPages.currentpage().getParameters().containsKey('clone') &&
        ApexPages.currentpage().getParameters().get('clone') == '1') {
            this.clone = [select id, amount, name from Opportunity where id = : o.id];
  // add any other clone prep defaults (e.g. modify the Oppo.name)
        }
}

public PageReference doClone() {
 PageReference resPg; 
 try {
      Opportunity o = this.clone(false,true); // don't copy the id
      insert o;
      resPg = new PageReference('/' + o.id);
      resPg.setRedirect(true);
  }
  catch (DmlException e) {ApexPages.addMessages(e);}
  return resPg;
}

}

Don't forget to Override the Clone standard button with the VF page above

| improve this answer | |
  • I see. Still a little confused about the VF page. Would I need to add all the fields in the VF page? Is there a default way to display what is shown in the standard object (case) form or do I have build everything in VF page I created? – ajl7519 Mar 20 '14 at 15:16
  • I build a custom VF page with only the fields that are changeable by user during the clone process – cropredy Mar 20 '14 at 16:03
  • I was able to get the full page, but still a little off on how to carry over values without actually inserting the record. Do you have quick sample of code you use? – ajl7519 Mar 20 '14 at 19:00
  • I added a cut-down version of the code - I had to strip out a bunch of stuff from my real code so pasted code may have typo but you should get the idea - the essence is to bind your VF page components to an SObject that you fetch from the database and then adjust in the constructor so when the page is displayed it has all the necessary defaults. You could also do this with a pageAction method. The user makes edits to the VF page, then clicks Save which does the DML – cropredy Mar 21 '14 at 1:46
  • Thank you! That was very helpful. Not 100% finished with the code, I know it will work once I'm completed. Thanks again. – ajl7519 Mar 27 '14 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.