1

UPDATE:


I have updated my APex code to the following:

public class attachRecPDFToQuote {
    
    private final Quote q; //Quote object
    
    //constructor
    public attachRecPDFToQuote(ApexPages.StandardController standardPageController) {
        q = (Quote)standardPageController.getRecord(); //instantiate the Quote object for the current record
    }
    
    //method called from the Visualforce's action attribute
    public PageReference attachPDF() {
        String skipPDF = ApexPages.currentPage().getParameters().get('doNotSavePDF');
        PageReference pdfPage = Page.SystemRec; //create a page reference to our Visualforce page
        Blob pdfBlob; //create a blob for the PDF content
        
        if (skipPDF != 'true') {
            pdfPage.getParameters().put('doNotSavePDF','true');
            
        }
        
        Attachment attach = new Attachment(parentId = q.Id, Name = 'pdfAttachmentDemo.pdf', body = pdfBlob); //create the attachment object
        insert attach; //insert the attachment
        
        //redirect the user
        PageReference pageWhereWeWantToGo = new ApexPages.StandardController(q).view(); //we want to redirect the User back to the Quote detail page
        pageWhereWeWantToGo.setRedirect(true); //indicate that the redirect should be performed on the client side
        return pageWhereWeWantToGo; //send the User on their way
    }
}

I am now met with this error: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Body]: [Body] Error is in expression '{!attachPDF}' in component apex:page in page systemrec: Class.attachRecPDFToQuote.attachPDF: line 23, column 1


I am using this reference: here
I want to: Create a button on the 'Quote' object that creates and attaches a PDF of a VisualForce page when selected
The issue I'm having: "Too many nested getContent calls" - infinite loop?

My VisualForce Code:

<apex:page action="{!attachPDF}" extensions="attachRecPDFToQuote" standardController="Quote" standardStyleSheets="false" showHeader="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" renderAs="pdf">
<apex:stylesheet value="{!$Resource.styleForSystemRec}"/>


<div class="headingDiv">
    <br></br><br></br><br></br>
    
    <div class="headingTag">
    <span>System Recommendation</span>
    </div>
    
    <div class="headingAddress">
    <span>48 Fisk Dr.</span><br></br>
    <span>Arden, NC</span><br></br>
    <span>28704</span><br></br>
    <span>(828)684-8441</span>
    </div>
    
    <br></br><br></br><br></br><br></br><br></br><br></br>
    <img class="logo" src="{!$Resource.LogoSHRedClear}"/>
    <h1> <i>Simply</i>Home Recommendation <br></br> for Independence-Granting Technology</h1>
    <p>This recommendation was assembled by a dedicated member of the <i>Simply</i>Home Customer Service team, <br></br>using a person-focused approach.</p>
    <br></br>
</div>

<hr class="pageLine" />

<div class="bodyDiv">
    <br></br><br></br><br></br>
    <div class="row">
          <div class="column">
            <p class="bodyP">
                
                <strong>Recommendation Prepared For: </strong><br></br>
                <span>Name and Role</span><br></br>
                <span>Client Name: </span><br></br>
                <span>48 Fisk Dr.</span><br></br>
                <span>Arden, NC</span><br></br>
                <span>28704</span><br></br>
                <span>(828)684-8441</span><br></br><br></br>
                
                <strong>Recommendation Prepared By: </strong><br></br>
                <span><i>Simply</i>Home</span><br></br>
                <span>48 Fisk Dr.</span><br></br>
                <span>Arden, NC</span><br></br>
                <span>28704</span><br></br>
                <span>(828)684-8441</span>
             </p>
            </div>
           <div class="column">
           <p class="bodyP">
               
               <strong> Site Address: </strong> <br></br>
               <span>48 Fisk Dr.</span><br></br>
               <span>Arden, NC</span><br></br>
               <span>28704</span><br></br><br></br>
               
               <strong> Concerns Addressed: </strong> <br></br>
               <span>Wandering and Elopement</span><br></br>
               <span>Kitchen/Cooking Safety</span><br></br>
               <span>Personal Care</span><br></br>
           </p>
           </div>
      </div>       
    <div class="clear">
    <hr class="pageLine" />
    <br></br><br></br><br></br>
    
    <apex:outputtext rendered="{IF(CONTAINS({!key},'Cooking'),true, false)}">
            <strong> Kitchen/Cooking Safety </strong>
            <span>The <i>Simply</i>Home System can be customized to support individuals during cooking, baking, and meal preparation routines, creating opportunities for independence and learning. Caregivers or staff can be alerted if concerns arise, such as the stove being left on. We may recommend stove sensors, motion sensors in the kitchen or dining areas, and smoke alarm monitors as part of these systems.
            Read more about Cooking Safety here, or meet Pearlie. 
            </span>
    </apex:outputtext>
    
   <strong> Please Note: </strong>
   <span> THIS SYSTEM RECOMMENDATION DOES NOT SERVE AS THE QUOTE FOR PRODUCTS AND SERVICES. Once you have decided which items you would like as a part of your customized system design, we will send a formal quote. </span>
    
    
    
    
    </div>
</div>

My Apex Code:

public class attachRecPDFToQuote {
    
    private final Quote q; //Quote object
    
    //constructor
    public attachRecPDFToQuote(ApexPages.StandardController standardPageController) {
        q = (Quote)standardPageController.getRecord(); //instantiate the Quote object for the current record
    }
    
    //method called from the Visualforce's action attribute
    public PageReference attachPDF() {
        
        //generate and attach the PDF document
        PageReference pdfPage = Page.SystemRec; //create a page reference to our Visualforce page
        Blob pdfBlob; //create a blob for the PDF content
        if (!Test.isRunningTest()) { //if we are not in testing context
            pdfBlob = pdfPage.getContent(); //generate the pdf blob
        } else { //otherwise, we are in testing context and getContent() gets funky so create the blob manually
            pdfBlob = Blob.valueOf('Some Text for a boring PDF file...');
        }
        Attachment attach = new Attachment(parentId = q.Id, Name = 'pdfAttachmentDemo.pdf', body = pdfBlob); //create the attachment object
        insert attach; //insert the attachment
        
        //redirect the user
        PageReference pageWhereWeWantToGo = new ApexPages.StandardController(q).view(); //we want to redirect the User back to the Quote detail page
        pageWhereWeWantToGo.setRedirect(true); //indicate that the redirect should be performed on the client side
        return pageWhereWeWantToGo; //send the User on their way
    }
}
2
  • There is a loop. You open a page, which on a page open calls a getContent method that and insert attachment. At the getContent method, page is opened again, and that lead to calling getContent once more and so on. What to do - add a URL param to do not call a PDF if it is present (so stop a recursion) or to use 2 different pages
    – kurunve
    Dec 7, 2020 at 16:30
  • @kurunve - Thank you! Can you explain how I would add a URL param? Dec 7, 2020 at 16:34

2 Answers 2

0

Main problem is that during execution of getContent, all the actions are called as well. That leads to an infinite loop, so if you open a page, on page load it calls getContent to get data for same page. During execution of that, all actions are executed, and that leads to a recursion.

One of the ways to prevent it - use a URL parameter to let action know when PDF should not be saved at all. Consider the following pseudocode:

public class attachRecPDFToQuote {
    
    private final Quote q; //Quote object
    
    //constructor
    public attachRecPDFToQuote(ApexPages.StandardController standardPageController) {
        q = (Quote)standardPageController.getRecord(); //instantiate the Quote object for the current record
    }
    
    //method called from the Visualforce's action attribute
    public PageReference attachPDF() {
        String skipPDF = ApexPages.currentPage().getParameters().get('doNotSavePDF');
        if (skipPDF != 'true') {
            PageReference pdfPage = Page.SystemRec; 
            Blob pdfBlob;
            pdfPage.getParametersMap().put('doNotSavePDF','true');
            /* SAME code as before */
        }
    }
}
1
  • I am still getting an error - I have updated the initial question above to show my changes and the new error. Thank you for your help Dec 7, 2020 at 17:11
0

I was able to solve the issue going a different route and using this article as a guide: [here][1]

My final APEX code was:

public class attachPDFToApplication {
    public Id recId {get;set;}
    Public List<Attachment> existingAttLst {get;set;}
    Public Assessment__c record {get;set;}
   
    //constructor
    public attachPDFToApplication(ApexPages.StandardController standardPageController) {
        recId = standardPageController.getId();
        record = (Assessment__c)standardPageController.getRecord();
        Datetime apllicationdate = datetime.now();   //field that will create the pdf
        String attName = 'SystemRec - '+ datetime.now() + '.pdf';
        existingAttLst  = new List<Attachment> ([Select id from Attachment where ParentId =: record.Id and Name =: attName limit 1]);
    }
   
    //method called from the Visualforce's action attribute
    public void attachPDF() {
        if(existingAttLst == null || existingAttLst.size() <1){
            Blob pdfBlob;
            PageReference pdfPage = Page.SystemRec2;
           
            pdfPage.getParameters().put('id',recId);
            pdfPage.setRedirect(true);
            try{
                pdfBlob = pdfPage.getContentAsPdf();
            }catch(exception e){
                pdfBlob = blob.valueOf('this is from excetion  '+e.getMessage());
                system.debug(e.getMessage());
            }
            system.debug('id==>'+recId );
            Attachment attach = new Attachment(ParentId = recId, Name = 'SystemRec - '+ datetime.now() + '.pdf', body = pdfBlob);
            insert attach;
        } else {
            system.debug('PDF already attached');
        }
        
    }
}

I had 2 VF pages, one with the content, and one as a wrapper.

VF Page 1 (content):

<apex:page standardcontroller="Assessment__c">
**Content**
</apex:page>

VF Page 2 (wrapper):

<apex:page standardcontroller="Assessment__c" extensions="attachPDFToApplication" action="{!attachPDF}" showHeader="false" applyHtmlTag="false" applyBodyTag="false" standardStylesheets="false" docType="html-5.0"  lightningstylesheets="true">
<apex:include pageName="SystemRec2" />
</apex:page>

Then, I created a button on the appropriate object to pull in the wrapper VF page. [1]: https://trailblazers.salesforce.com/answers?id=9063A000000puiWQAQ

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .