I am creating a simple project to learn Salesforce and APEX. Currently, I am taking in a file that the user uploads, parsing it, and reading it line by line to check for a particular value, and then uploading a Standard object.
The readFile() method is the method that performs all the business logic. This tiny learning project I thought of is to use the current Contact's email address as the filter in which to read a .csv file that the user uploads, which contains a list of email addresses and each's associated Gravitar URL.
My current error is the following:
Unknown method 'ContactStandardController.readFile()' Error is in expression '{!readFile}' in component in page gravitarimport:uploadgravitarurl
Here is my Visualforce page:
<apex:page standardController="Contact" extensions="GravitarImportExtension" sidebar="true">
<apex:outputPanel id="all">
<apex:form>
<apex:sectionHeader title="Upload data from CSV file"/>
<apex:pagemessages />
<apex:pageBlock >
<!-- Component to allow user to upload file from local machine -->
<center>
<apex:inputFile value="{!contentFile}" filename="{!nameFile}" />
<apex:commandButton action="{!readFile}" value="Upload File" rerender="all" id="theButton" style="width:70px;" >
<apex:param name="paramValue" value="{!contentFile}" assignTo="{!csvFILE}"></apex:param>
<apex:param name="paramValue2" value="{!currentRecord}" assignTo="{!currentRecord}"></apex:param>
</apex:commandButton>
<br/> <br/>
<font color="blue"> <b>Note: Please use the standard template to upload a Gravitar URL. <a href="https://drive.google.com/open?id=0B6RcI99u5FjFbWlHRFREdWYyUjQ" target="_blank"> Click here </a> to download the template. </b> </font>
</center>
</apex:pageBlock>
</apex:form>
</apex:outputPanel>
</apex:page>
My Controller Extension:
public class GravitarImportExtension {
private ApexPages.StandardController controller;
public string nameFile{get;set;}
public Blob contentFile{get;set;}
String[] filelines = new String[]{};
public Blob csvFILE {get; set;}
Contact currentRecord;
public GravitarImportExtension(ApexPages.StandardController controller) {
this.currentRecord = (Contact)controller.getRecord();
currentRecord = [SELECT Email FROM Contact WHERE Id = :currentRecord.Id];
}
//public GravitarImportExtension(){}
public void readFile(Contact currentRecord, Blob contentFile) {
try {
// Convert the uploaded Blob file into a String in order to be parsed
nameFile = convertBlobToString(contentFile,'ISO-8859-1');
// Parse every row into a new line
fileLines = nameFile.split('\n');
// Iterate through the lines and populate the Gravitar_URL custom field with the Gravitar URL field in the CSV file
for (Integer i=1; i<fileLines.size(); i++) {
String[] recordContents = new String[]{};
recordContents = fileLines[i].split(',');
if (recordContents[0] == currentRecord.Email) {
currentRecord.Gravitar_URL__c = recordContents[1];
} else {
ApexPages.Message errormsg = new ApexPages.Message(ApexPages.severity.ERROR,'Contact was not found in provided data');
}
try {
update currentRecord;
ApexPages.Message successmsg = new ApexPages.Message(ApexPages.severity.CONFIRM, 'Contact\'s Gravitar URL successfully imported.');
ApexPages.addMessage(successmsg);
} catch (Exception e) {
ApexPages.Message errormsg = new ApexPages.Message(ApexPages.severity.ERROR,'An error has occured while updating the contact'+e.getMessage());
ApexPages.addMessage(errormsg);
}
}
}
catch(Exception e) {
ApexPages.Message errormsg = new ApexPages.Message(ApexPages.severity.ERROR,'An error has occured reading the CSV file'+e.getMessage());
ApexPages.addMessage(errormsg);
}
//return null;
}
public String convertBlobToString(Blob input, String inCharset){
String hex = EncodingUtil.convertToHex(input);
System.assertEquals(0, hex.length() & 1);
final Integer bytesCount = hex.length() >> 1;
String[] bytes = new String[bytesCount];
for(Integer i = 0; i < bytesCount; ++i)
bytes[i] = hex.mid(i << 1, 2);
return EncodingUtil.urlDecode('%' + String.join(bytes, '%'), inCharset);
}
}
My Test Class:
@isTest
private class GravitarImportExtensionTest {
@isTest static void testingImport() {
// Create a test Contact
Contact currentRecord = new Contact();
currentRecord.Email='jmccreary@credera.com';
currentRecord.GravitarImport__Gravitar_URL__c = 'https://s.gravatar.com/avatar/70796209a2c14dc50962c8ab05b394cb?s=80';
// Build the .csv file
String csvHeader = 'Email, Gravitar URL\n';
String csvFinalString = csvHeader;
String csvRecord = currentRecord.Email+','+currentRecord.GravitarImport__Gravitar_URL__c+'\n';
csvFinalString = csvFinalString + csvRecord;
Blob csvBlob = Blob.valueOf(csvFinalString);
// Create an instance of the object in order to invoke the readFile() method
GravitarImportExtension gravitarClass = new GravitarImportExtension();
gravitarClass.readFile(currentRecord, csvBlob);
// Test that the return message is the successful confirmation message
List<ApexPages.Message> messages = ApexPages.getMessages();
boolean flag = false;
System.debug(messages);
for(Apexpages.Message message : messages) {
String messageDetail = message.getDetail();
if (message.getDetail() != null) {
flag = true;
}
System.assertEquals(true, flag);
}
}
}
My code is of course very crude. Specifically, I have tried the "assignTo" param method (as shown here) and I have also seen these two attempts using a current page and scripts, but I do not know which is a best practice: Passing method parameters with apex:actionFunction
I believe the simplest test here is to ensure whether the confirm Apex message is displayed. I researched that the convertBlobToString() method will also be included in my coverage since the tested method "readFile()" calls it.
The readFile method in my extension initially worked flawlessly without any parameters (as I assume that's what the get and set methods at the top were for, correct?). However, in the process of creating my test class I have added the two parameters, so that in my test I can include a newly built Contact record and a .csv file within the test for use in the method, instead of the one read from the page, hence my parameters.
I am coming from a few weeks of learning Java, so not being able to directly pass parameters is frustrating. Let me know if you need any clarification, any help would be appreciated!