1
votes

I've got one head scratcher of a problem that I can't seem to find a solution for.

I'm doing a VisualForce page as a PDF for a client, this is basically a neatly formatted report, no input text boxes etc and i'm having trouble accessing some data - namely attachments.

Attachments are normally part of opportunities, however, this is a fairly customised setup so what we have is two custom objects hanging off the opportunities table that stores the data. I've retrieved all the regular data apart from image attachments.

Basically Opportunities has a custom object SFDC_520_Quote__c which the client calls a 'room', each room then has a selection of SFDC_520_QuoteLine__c objects attached to it which have links to products etc, this I can do.

However, images which are attached at this 'room' level are given a ParentID of the SFDC_520_Quote__c.id field which is making it difficult for me to get a SOQL statement together to read the data as there's no defined relationship between SFDC_520_Quote__c and Attachment.

I realise I could add a field but i've no idea how i'd update the existing data in the time available to me as i'm picking up from someone else leaving.

What I ideally need to do in my visualforce page is pass a parameter to the controller class during a repeat loop and then call another getter which can act on it but i'm having trouble setting the variable on the controller side.

Example (heavily truncated):

<apex:page renderAs="pdf" standardController="Opportunity" extensions="myController">
  <apex:repeat value="{!allRooms}" var="room">
    <h1>{!room.Name}</h1>
    <apex:repeat value="{!room.QuoteLines__r}" var="ql">
      <p>{!ql.Product2__r.Name}: {!ql.Product2__r.Description} - {!ql.Description__c}</p>
    </apex:repeat>
  </apex:repeat>
</apex:page>

My controller:

public class myController {
  public List<SFDC_520_Quote__c> getAllRooms() {
    List<SFDC_520_Quote__c> roomWithQuoteList = [select id, Name, Quote_Amount__c, Quote__c, 
        (select Item_Order__c, Product2__r.ProductCode, Product2__r.Name, Product2__r.Description, Description__c from QuoteLines__r order by Item_Order__c) 
        from SFDC_520_Quote__c where Opportunity__c =: ApexPages.currentPage().getParameters().get('id')];

    return roomWithQuoteList;    
  }

}

The above works fine, but after the first inner I need to get the attachments. Attachments are based on room.id so ideally I need to pass room.id to some getter like 'getAttachments' except you can't pass parameters to a getter from visualforce.

So, it might look something like:

<apex:page renderAs="pdf" standardController="Opportunity" extensions="myController">
  <apex:repeat value="{!allRooms}" var="room">
    --> something to call a setter with value from {!room.id} <--
    <h1>{!room.Name}</h1>
    <apex:repeat value="{!room.QuoteLines__r}" var="ql">
      <p>{!ql.Product2__r.Name}: {!ql.Product2__r.Description} - {!ql.Description__c}</p>
    </apex:repeat>
    <apex:repeat value="{!allAttachments}" var="attachment">
      <apex:image height="200px" value="{!URLFOR($Action.Attachment.Download, attachment.Id)}"/>
    </apex:repeat>
  </apex:repeat>
</apex:page>

And then adding to the controller:

private String oppParentID;

public void setParentID(string theID) {
  oppParentID = theID;
}

public List<Attachment> getAllAttachments() {
  List<Attachment> theAttachments = [select Id, Name, ContentType, .... from Attachment where parentiD =: oppParentID];
  return theAttachments;
}

That, or a way to modify my original getAllRooms() method to do the above in one go, there's no relationship field and I can't figure out how to do a subselect with a WHERE that compiles properly.

I've seen tons of examples that all talk about using the query string parameters but there's no form involved, no refresh, just a call to a VF page.

Please help.

1
Update: Its been suggested the only way to do this may be with an apex componentJamesB

1 Answers

1
votes

JamesB,

It looks like you already have the solution in the SOQL query used in your getAllRooms method!

Here's what you wrote:

List<SFDC_520_Quote__c> roomWithQuoteList = [select id, Name, Quote_Amount__c, Quote__c, 
        (select Item_Order__c, Product2__r.ProductCode, Product2__r.Name, Product2__r.Description, Description__c from QuoteLines__r order by Item_Order__c) 
        from SFDC_520_Quote__c where Opportunity__c =: ApexPages.currentPage().getParameters().get('id')];

It seems to me all you have to do is add an extra element to the SOQL query:

List<SFDC_520_Quote__c> roomWithQuoteList = [select id, Name, Quote_Amount__c, Quote__c, 
        (select Item_Order__c, Product2__r.ProductCode, Product2__r.Name, Product2__r.Description, Description__c from QuoteLines__r order by Item_Order__c),
        (select Id, Name, ContentType from Attachments)
        from SFDC_520_Quote__c where Opportunity__c =: ApexPages.currentPage().getParameters().get('id')];

This should allow your nested repeat to work with a minor tweak to the 2nd repeat:

<apex:page renderAs="pdf" standardController="Opportunity" extensions="myController">
  <apex:repeat value="{!allRooms}" var="room">
    <h1>{!room.Name}</h1>
    <apex:repeat value="{!room.QuoteLines__r}" var="ql">
      <p>{!ql.Product2__r.Name}: {!ql.Product2__r.Description} - {!ql.Description__c}</p>
    </apex:repeat>
    <apex:repeat value="{!room.Attachments}" var="attachment">
      <apex:image height="200px" value="{!URLFOR($Action.Attachment.Download, attachment.Id)}"/>
    </apex:repeat>
  </apex:repeat>
</apex:page>