Cause: Transaction Scope
I've hit this before, and concluded this is due to how getContent is likely implemented internally. As per the Apex Documentation on transaction handling...
all changes are committed to the database only after all operations in the transaction finish executing
So the problem is until your database changes are committed, effectively not until after submitApplication method completes, no other code executions will see the changes to the record. I suspect the platform getContent method must run in a separate transaction context and thus cannot see the changes your code is making.
Solution: Chaining Execution Contexts
The solution is to invoke your logic that calls getContent and creates the attachment in a subsequent execution context (providing this one completes successfully). As it seems all async Apex features (Batch, @future) block getContent or fail silently.
We can create a new execution context via apex:actionFunction, which is invoked once the command button AJAX is complete. This example performs some DML (in my test case insert), then sets a controller member variable to pass some context to the second method invoked by the actionFunction.
public with sharing class CreateRecordAndAttachPDF {
public Id parentId {get;set;}
public PageReference createRecord()
{
Test__c test = new Test__c();
test.A_Number__c = 42;
insert test;
parentId = test.id;
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Info, 'Please wait while the attachment is made...'));
return null;
}
public PageReference attachPDF()
{
Attachment applicationpdf = new Attachment();
applicationpdf.Body = Page.mypdf.getContentAsPdf();
applicationpdf.ContentType = '.pdf';
applicationpdf.Name = 'Application PDF';
applicationpdf.Name += '.pdf';
applicationpdf.ParentId = parentId;
insert applicationpdf;
parentId = null;
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Info, 'PDF has been attached!'));
return null;
}
}
This is the Visualforce page i used...
<apex:page controller="CreateRecordAndAttachPDF">
<apex:form id="myform">
<apex:pageMessages />
<apex:commandButton
action="{!createRecord}"
value="Create Record and Attach PDF"
rendered="{!ISNULL(ParentId)}"
onComplete="attachPDF();"
reRender="myform"/>
<apex:actionFunction
name="attachPDF"
action="{!attachPDF}"
reRender="myform"/>
</apex:form>
</apex:page>
It shows this initially...
Then when clicked this...
Then once attached this...
Hope this helps!
On the attaching the PDF part of your question, you can connect your button to a controller method as described in e.g. Call Apex Class From A Custom Button.
To generate the PDF and attach it you can use the getContentAsPDF method and insert the Attachment:
global class MyClass {
webservice static void attachPdf(Id customObjectId) {
PageReference pr = Page.YourPageName;
// Add parameters (if any) passed from the custom button or queried locally
pr.getParameters().put('id', ...);
insert new Attachment(
ParentId = customObjectId,
Name = 'Whatever Name You Want',
Body = pr.getContentAsPDF(),
ContentType = 'application/pdf'
);
}
}
Best Answer
Unfortunately, I think you are out of luck for this. When the standard Salesforce layout is used for a Record (or even the Printer friendly version) it is served from a different domain to Visualforce (thanks to @mattandneil for this one) which then causes problems in the PDF generation.
For example, the following Apex causes an Internal Salesforce Error in my org and reports "PDF generation failed. Check the page markup is valid."
Checkout this question/answer, ignore the bits about BatchPDF as it's not relevant to your case, but the accepted answer has some clever Apex to strip out unnecessary tags etc. and return only valid HTML that can be displayed in a PDF (this still requires a Visualforce page/Controller - but it is very simple).
You might want to review this document which gives some general tips on creating PDFs.
The other thing you might consider is actually building the PDF in your Apex as described in this blog post. Again, this might be more effort than using a Visualforce page (be careful of unsupported tags).