With a little side of applesauce...

Friday, June 24, 2011

Using Coldfusion to retrieve Wufoo form entries

Instructions
------------

0. cd /path/to/your/wufoo/Wufoo.cfc
1. copy Wufoo.cfc to your desired webfolder
2. vi Wufoo.cfc and change variables.subdomain and variables.apiKey to your API Key and subdomain.
- variables.subdomain = erikin
- variables.apiKey = 16-character alpha-numeric string (api key is tied to the user, and can be reset on the API information page).
(a. login to wufoo admin
b. click on the form tab
c. choose any form, and click code
d. click on API information
e. copy the 16-character alpha-numeric string
)
3. build the calling page in the same directory as Wufoo.cfc, (refer to example.com for either javascript or coldfusion usage).
- you can use either the form name, or hashed form name, (hashed form name is recommended, as it will remain
the same, even if the form is renamed:
(a. login to wufoo admin
b. click on the form tab
c. choose any form, and click code
d. click on API information
e. scroll to bottom of field list and copy the 'HASH' value. (ie Hash m7p5s7)
)


Here is my example.cfm, which shows how to handle the entries using either jQuery or Coldfusion:
<!--- 
You can choose to one or both of the following lines:
1. cfset cfcWufooGetter... is used when you want to make the calls using Coldfusion
2. cfajaxproxy is used if you want to use Javascript to get your Wufoo data
--->
<!--- instantiate our wufoo getter library for CF object if we are using CF to display the data --->
<cfset cfcWufooGetter = CreateObject('component', 'Wufoo').init() />
<!--- setup our CF to JS proxy if we are handling the wufoo data with javascript --->
<cfajaxproxy cfc="Wufoo" jsclassname="w">

<!--- start our HTML --->
<html>
<head>
<!--- load jquery to ease life --->
<script type="text/javascript" src="/js/jquery/jquery-1.5.js"></script>
<script type="text/javascript">
// acquireEntires() is an example of using javascript to get your data
function acquireEntries()
{
// instantiate the js object which proxies back to Wufoo.cfc
var n = new w();
// call makeCall() from Wufoo.cfc with the following params:
// 1. the name or hash of the form you want to access
// 2. cf or json.
// - cf returns a coldfusion query
// - json returns a coldfusion version of json
//
// makeCall() returns an array of form entries.
var x = n.makeCall( 'z7p8s7', 'json' );

// Grab our div so that we can add our new data
var mystring = $('#q');
// loop through the array of entries, and print an entry header
for ( var iter=0;iter<x.length;iter=iter+1 ) {
mystring.append( '<h2>Entry ' + iter + '</h2>');
// loop through the field title:value pairs for an entry
for ( var iter2=0;iter2<x[iter].DATA.length;iter2=iter2+1 ) {
mystring.append( '<strong>' + x[iter].DATA[iter2][0] + ':</strong> ' + x[iter].DATA[iter2][1] + '<br />');
}
}

// push our modified HTML back into the DOM
$("#q").text( mystring );
}
</script>
</head>

<body>
<!--- This is simply to allow you to click on a button. Feels good, doesn't it? --->
<input type="submit" id="clickme" value="clickme" onClick="acquireEntries();" />
<!--- Here is our empty div which will hold our title:value pairs --->
<div id="q"></div>


<!--- This is simply a call using coldfusion, with a cfdump to show the array of entries --->
<!---
// call makeCall() from Wufoo.cfc with the following params:
// 1. the name or hash of the form you want to access
// 2. cf or json.
// - cf returns a coldfusion query
// - json returns a coldfusion version of json
//
// makeCall() returns an array of form entries.
--->
<cfset x2 = cfcWufooGetter.makeCall( 'music-camp', 'cf' ) />
<cfdump var='#x2#' />

</body>
</html>



Here is Wufoo.cfc:
 <cfcomponent name="Wufoo"
extends="class.WufooGetter"
displayname="Wufoo"
hint="Main init config for Wufoo libraries

@author Shannon Eric Peevey speeves@erikin.com '11
">

<cffunction name="init"
access="public"
output="no"
hint="
We use this to hide our api key from prying eyes.

1. Copy this file to your class directory.
2. Add your subdomain and api key below

It will automatically load WufooGetter.cfc.
">
<cfset variables.subdomain = 'SUBDOMAIN HERE' />
<cfset variables.apiKey = 'PUT YOUR API KEY HERE' />
<cfset variables.domain = 'wufoo.com' />
<cfset variables.formPath = 'api/v3/forms/' />

<cfreturn this />
</cffunction>
</cfcomponent>



And, here is WufooGetter.cfc:
<cfcomponent name="WufooGetter"
displayname="WufooGetter"
hint="Utility class for sending Wufoo API requests to wufoo
@author Shannon Eric Peevey speeves@erikin.com '11
">

<cffunction name="getFieldNames"
access="public"
returnType="query"
output="no"
hint="
Wufoo asks us to make a second query to the Fields API to acquire the field names for a given form

This function:
1. takes the name of a form, and calls the Fields API.
2. converts the JSON response into a Coldfusion object
3. loops through the array of fields, checking for subfields, and then creates a
flat query object so that we can match rows in a query of queries in makeCall()
(allowing us to remove the Field1, Field2 business, and return an actual field
title/label with the value)

">

<cfargument name="formName" type="string" required="true" hint="name of the form" />

<cfset newJson = '' />
<cfset newQuery = queryNew( "id, title") />
<cfset u = 'https://#variables.subdomain#.#variables.domain#/#variables.formPath##formName#/fields.json' />


<!--- get the field names for formName --->
<cfhttp method="get" url="#u#" username="#variables.apikey#" result="fields" password="test" throwOnError="yes" />

<cftry>
<!--- convert the fieldnames response into a CF object --->
<cfset newJson = DeserializeJSON( fields.FileContent.toString("UTF-8") ) />

<!--- loop through each field entry --->
<cfloop array="#newJson.Fields#" index="f">

<!--- it is possible that we have subfields, (for fancy pants fields) --->
<cfif IsDefined('f.Subfields')>
<cfloop array="#f.SubFields#" index="s">
<cfset queryAddRow(newQuery) />
<cfset querySetCell( newQuery, "id", s.ID) />
<cfset querySetCell( newQuery, "title", s.LABEL) />
</cfloop>
<cfelse>
<cfset queryAddRow(newQuery) />
<cfset querySetCell( newQuery, "id", f.ID) />
<cfset querySetCell( newQuery, "title", f.TITLE) />
</cfif>
</cfloop>
<cfcatch type="any">
<cfset errorMsg = "Call to Wufoo API FAILED. ERROR DETAIL: #fields.errorDetail# URL: #u# " />
<cflog application="yes" text="#DateFormat(now(),'mm-dd-yyyy')#.#TimeFormat(now(), 'HH:mm:ss')#|#errorMsg#|#CGI.CF_TEMPLATE_PATH#|#CGI.REMOTE_ADDR#|#CGI.SERVER_NAME#|#CGI.HTTP_USER_AGENT#|#CGI.HTTP_REFERER#" />
</cfcatch>
</cftry>

<cfreturn newQuery />
</cffunction>

<cffunction name="makeCall"
access="remote"
output="no"
hint="
makeCall() combines the entries and fields API calls into
either a coldfusion array of queries, or json

This function:
1. takes the name of a form, and the desired returntype, (default: json) (cf|json).
2. call the entries API.
3. call the fields API
4. loop through each entries response and convert them into a coldfusion object
- Then convert them into a query with the cols (id, fieldValue), so that
we can match them against the fields API response
5. for each entrie, use the query of queries to match field names with field values.
6. append each query of queries result to arrEntries.
7. if returntype EQ json, then we change our cf object back into json (an array of (COLUMN, DATA) values)
8. return arrEntries

">

<cfargument name="formName" type="string" required="true" hint="name of the form" />
<cfargument name="returnType" type="string" required="false" default="json" hint="cf or json" />

<cfset init() />
<cfset newJson = '' />
<cfset j = '' />
<cfset arrEntries = ArrayNew(1) />
<cfset u = 'https://#variables.subdomain#.#variables.domain#/#variables.formPath##formName#/entries.json' />

<!--- get our get our form entries --->
<cfhttp method="get" url="#u#" username="#variables.apikey#" result="entries" password="test" throwOnError="yes" />

<cftry>
<!--- get our field names for this form (a query) --->
<cfset fieldsQuery = getFieldNames( formName ) />

<!--- convert our entries response to a coldfusion object --->
<cfset newJson = DeserializeJSON( entries.FileContent.toString("UTF-8") ) />

<!--- loop through our array of form entries to match field names with values --->
<cfloop array="#newJson.Entries#" index="e">
<!--- Create a new query and loop over keys in the entry response struct. --->
<cfset entryQuery = QueryNew( "id, fieldValue" ) />
<cfloop index="strKey" list="#StructKeyList( e )#" delimiters=",">
<cfset queryAddRow(entryQuery) />
<cfset querySetCell( entryQuery, "id", strKey) />
<cfset querySetCell( entryQuery, "fieldValue", Evaluate( "e.#strKey#" ) ) />
</cfloop>

<!--- join our queries to match field names with values --->
<cfquery dbtype="query" name="j">
select fieldsQuery.title, entryQuery.fieldValue from fieldsQuery, entryQuery
WHERE fieldsQuery.id = entryQuery.id
</cfquery>

<!--- append this query object to our return result --->
<cfset ArrayAppend( arrEntries, j) />

</cfloop>
<!--- if returntype EQ json, we convert arrEntries into json --->
<cfif returnType NEQ 'cf'>
<cfset j = SerializeJSON( arrEntries ) />
</cfif>
<cfcatch type="any">
<cfset errorMsg = "Call to Wufoo API FAILED. ERROR DETAIL: #entries.errorDetail# URL: #u# " />
<cflog application="yes" text="#DateFormat(now(),'mm-dd-yyyy')#.#TimeFormat(now(), 'HH:mm:ss')#|#errorMsg#|#CGI.CF_TEMPLATE_PATH#|#CGI.REMOTE_ADDR#|#CGI.SERVER_NAME#|#CGI.HTTP_USER_AGENT#|#CGI.HTTP_REFERER#" />
</cfcatch>
</cftry>

<cfreturn arrEntries />
</cffunction>
</cfcomponent>


No comments: