This idea came from a discussion today on the cf-newbie mail list. Zelda (real name, or real name in the sig, either way, cool) described a situation where she need to...

  • Process a form
  • Turn the form data into a PDF
  • Email the PDF

This isn't a complex process, but it's an interesting example of where you can combine simple tasks in ColdFusion into something a bit more complex. I thought it would make an excellent entry in my ColdFusion Sample series. What follows is my take on how one could do this. Let's begin by creating a simple form.

<form method="post"> <h2>Order Request / Kuat Drive Yards</h2>

<p> Thank you for your interest in ordering form Kuat Drive Yards. Please fill out the form below and be as complete as possible with your needs. </p>

<cfoutput> <cfif structKeyExists(variables, "errors")> <p> <b>Please correct these errors:<br> #errors# </b> </p> </cfif>

<p> <label for="name">Your Name:</label> <input type="text" name="name" id="name" value="#form.name#"><br/> </p>

<p> <label for="email">Your Email:</label> <input type="text" name="email" id="email" value="#form.email#"><br/> </p>

<p> <label for="orderrequest">Your Request:</label><br/> <textarea name="orderrequest" id="orderrequest">#form.orderrequest#</textarea> </p> </cfoutput>

<p> <input type="submit" name="submit" value="Send Request"> </p> </form>

Nothing too complex here. I've got 3 main form fields and a bit of logic to handle errors. Where that variable comes from, and the form fields themselves, will get to in a minute. With a bit of styling, this is our result.

Ok, now let's actually build in the form processing logic. In this version, I've got everything done except what we want to happen with the form when everything is entered correctly.

<cfparam name="form.name" default=""> <cfparam name="form.email" default=""> <cfparam name="form.orderrequest" default="">

<cfset showForm = true> <cfif structKeyExists(form, "submit")> <cfset errors = ""> <cfset form.name = trim(htmlEditFormat(form.name))> <cfset form.email = trim(htmlEditFormat(form.email))> <cfset form.orderrequest = trim(htmlEditFormat(form.orderrequest))>

<cfif form.name is ""> <cfset errors = errors & "Include your name.<br/>"> </cfif> <cfif form.email is "" or not isValid("email", form.email)> <cfset errors = errors & "Include your email address.<br/>"> </cfif> <cfif form.orderrequest is ""> <cfset errors = errors & "Include your order request.<br/>"> </cfif>

<cfif errors is ""> <cfset showForm = false> </cfif>

</cfif>

<html>

<head> <title>Order Request / Kuat Drive Yards</title> <style> #orderForm { width: 500px; margin-left: auto; margin-right: auto; margin-top: 10px; background-color: white; padding: 10px; }

input[type='text'] { width: 250px; float: right; } textarea { width: 100%; height: 200px; }

body { background-color: #c0c0c0;; } </style> </head>

<body>

<div id="orderForm">

<cfif showForm> <form method="post">

<h2>Order Request / Kuat Drive Yards</h2>

<p> Thank you for your interest in ordering form Kuat Drive Yards. Please fill out the form below and be as complete as possible with your needs. </p>

<cfoutput> <cfif structKeyExists(variables, "errors")> <p> <b>Please correct these errors:<br> #errors# </b> </p> </cfif>

<p> <label for="name">Your Name:</label> <input type="text" name="name" id="name" value="#form.name#"><br/> </p>

<p> <label for="email">Your Email:</label> <input type="text" name="email" id="email" value="#form.email#"><br/> </p>

<p> <label for="orderrequest">Your Request:</label><br/> <textarea name="orderrequest" id="orderrequest">#form.orderrequest#</textarea> </p>

</cfoutput> <p> <input type="submit" name="submit" value="Send Request"> </p> </form>

<cfelse> <h2>Thank you</h2> <p> Your order request has been received. Thank you. </p> </cfif>

</div>

</body> </html>

Scrolling from the top to the bottom, you can see I've paramed my form fields first. This allows me to always assume they exist and use them in the form right away. Whenever an error occurs and we redisplay the form, this allows for keeping their previous data in the form. If you don't do this, your users will hate you. I'm using a simple variable, showForm, that will keep track of whether or not we need to display the form.

My form processing logic is rather simple. Notice I trim and htmlEditFormat all the fields. Then I simply ensure they are all not blank. Only the email field gets a bit of extra love with the isValid function. Now I should be able to test my form. I can try leaving a few fields blank, hitting submit, and ensuring I get my error messages. The error message should change based on what I did wrong and the form should remember the fields I entered. Nice. Ok, now for the last bits.

First - generating a PDF is incredibly simple. I create my PDF from the form input using the cfdocument tag.

<!--- create a PDF from the request: ---> <cfdocument format="pdf" name="pdfData"> <cfoutput> <h2>Order Request</h2> <p> Order made by #form.name# (#form.email#) on #dateFormat(now(), "mm/dd/yy")# at #timeFormat(now(), "h:mm tt")#. </p> <p> The request was for: </p> <p> #form.orderrequest# </p> </cfoutput> </cfdocument>

While you've probably seen cfdocument before, make note of the name attribute. This tells ColdFusion to store the PDF bits in a variable instead of saving it or writing it out to screen. Now let's send our email:

<cfmail to="raymondcamden@gmail.com" from="#form.email#" subject="Order Request"> <cfmailparam disposition="attachment" file="request.pdf" type="application/pdf" content="#pdfData#" > An order request has been filed. See the attached PDF for details. </cfmail>

Nothing too fancy here. I send the email and attach the document. Make note of the content attribute of the cfmailparam tag. This allows me to attach the PDF and skip saving it to the file system. This is not in the PDF for the CFML 9 reference but is in the online version.

And that's it. If you're curious about the PDF I've attached it to the blog entry. And yes - this is a bit of a silly example. I didn't really need to create a PDF for 3 simple fields, but if your business process requires a PDF to be generated and emailed, hopefully this demonstrates how simple it is in ColdFusion. The full code of the template I used may be found below.

<cfparam name="form.name" default=""> <cfparam name="form.email" default=""> <cfparam name="form.orderrequest" default="">

<cfset showForm = true> <cfif structKeyExists(form, "submit")> <cfset errors = ""> <cfset form.name = trim(htmlEditFormat(form.name))> <cfset form.email = trim(htmlEditFormat(form.email))> <cfset form.orderrequest = trim(htmlEditFormat(form.orderrequest))>

<cfif form.name is ""> <cfset errors = errors & "Include your name.<br/>"> </cfif> <cfif form.email is "" or not isValid("email", form.email)> <cfset errors = errors & "Include your email address.<br/>"> </cfif> <cfif form.orderrequest is ""> <cfset errors = errors & "Include your order request.<br/>"> </cfif>

<cfif errors is "">

<!--- create a PDF from the request: ---> <cfdocument format="pdf" name="pdfData"> <cfoutput> <h2>Order Request</h2> <p> Order made by #form.name# (#form.email#) on #dateFormat(now(), "mm/dd/yy")# at #timeFormat(now(), "h:mm tt")#. </p> <p> The request was for: </p> <p> #form.orderrequest# </p> </cfoutput> </cfdocument>

<cfmail to="raymondcamden@gmail.com" from="#form.email#" subject="Order Request"> <cfmailparam disposition="attachment" file="request.pdf" type="application/pdf" content="#pdfData#" > An order request has been filed. See the attached PDF for details. </cfmail> <cfset showForm = false> </cfif>

</cfif>

<html>

<head> <title>Order Request / Kuat Drive Yards</title> <style> #orderForm { width: 500px; margin-left: auto; margin-right: auto; margin-top: 10px; background-color: white; padding: 10px; }

input[type='text'] { width: 250px; float: right; } textarea { width: 100%; height: 200px; }

body { background-color: #c0c0c0;; } </style> </head>

<body>

<div id="orderForm">

<cfif showForm> <form method="post">

<h2>Order Request / Kuat Drive Yards</h2>

<p> Thank you for your interest in ordering form Kuat Drive Yards. Please fill out the form below and be as complete as possible with your needs. </p>

<cfoutput> <cfif structKeyExists(variables, "errors")> <p> <b>Please correct these errors:<br> #errors# </b> </p> </cfif>

<p> <label for="name">Your Name:</label> <input type="text" name="name" id="name" value="#form.name#"><br/> </p>

<p> <label for="email">Your Email:</label> <input type="text" name="email" id="email" value="#form.email#"><br/> </p>

<p> <label for="orderrequest">Your Request:</label><br/> <textarea name="orderrequest" id="orderrequest">#form.orderrequest#</textarea> </p>

</cfoutput> <p> <input type="submit" name="submit" value="Send Request"> </p> </form>

<cfelse> <h2>Thank you</h2> <p> Your order request has been received. Thank you. </p> </cfif>

</div>

</body> </html>

Download attached file.