The Web application framework provides a simple way to customize the look of error messages that can occur while users are accessing your pages. As you know, error messages might appear because of syntax problems in your code, because of database connection problems, or just because user have left out one or more required fields while filling out a form. The application framework lets you customize any of these error messages. You can even hide them from the user's view entirely if you want. This enables you to maintain a consistent look and feel throughout your application, even when those dreaded error messages occur. You even have multiple ways to handle exceptions. We will cover both, dealing with the simplest solution first. Introducing the <cferror> TagYou use the <cferror> tag to specify how error messages should be displayed. Customizing the error messages that appear throughout your application is generally a two-step process:
Table 19.5 shows the attributes supported by the <cferror> tag.
The next two sections discuss how to customize the error messages displayed for exception errors (syntax errors, database errors, and so on) and validation errors (when the user fails to fill out a form correctly). Request vs. Exception Error TemplatesIf you want to customize the way error messages are displayed, you first must create an error display template. This template is displayed to the user whenever a page request can't be completed because of some type of uncaught error condition. ColdFusion actually allows you to create two types of error display templates:
In general, the best practice is to create one template of each type. Then the exception template is displayed most often, unless the error is so serious that ColdFusion can't safely continue interpreting CFML tags, in which case the request template is displayed. The request template also kicks in if the exception template itself causes an error or can't be found. NOTE If you don't care about being able to use CFML tags in these error display templates, you can just create the request template and skip creating the exception one. NOTE For those history buffs out there, the request type of error display template is a holdover from earlier versions of ColdFusion. At one time, you could never respond intelligently to any type of error. Thankfully, those days are over. Creating a Customized Request Error PageTo create the request display template, do the following:
Listing 19.9 is a good example of a request error display template. Note that no <cfoutput> or other CFML tags are present. Also note that the only variables used are the special ERROR variables mentioned previously. Listing 19.9. ErrorRequest.cfmCustomizing the Display of Error Messages<!--- Filename: ErrorRequest.cfm Created by: Nate Weiss (NMW) Please Note Included via <CFERROR> in Application.cfc ---> <html> <head><title>Error</title></head> <body> <!--- Display sarcastic message to poor user ---> <h2>Who Knew?</h2> <p>We are very sorry, but a technical problem prevents us from showing you what you are looking for. Unfortunately, these things happen from time to time, even though we have only the most top-notch people on our technical staff. Perhaps all of our programmers need a raise, or more vacation time. As always, there is also the very real possibility that SPACE ALIENS (or our rivals at Miramax Studios) have sabotaged our website.<br> <p>That said, we will naturally try to correct this problem as soon as we possibly can. Please try again shortly. <!--- Provide "mailto" link so user can send email ---> <p>If you want, you can <a href="mailto:#ERROR.mailTo#">send the webmaster an email</a>. <p>Thank you.<br> <!--- Maybe the company logo will make them feel better ---> <img src="/books/2/448/1/html/2/../images/logo_b.gif" width="73" height="73" alt="" border="0"> <!--- Display the actual error message ---> <blockquote> <hr><font size="-1" color="gray">#ERROR.diagnostics#</font> </blockquote> </body> </html> NOTE ColdFusion also provides the <cftry> and <cfcatch> tags, which enable you to trap specific errors and respond to or recover from them as appropriate. See Chapter 32, "Error Handling," for details. Listing 19.10 shows how to use the <cferror> tag in your Application.cfc file. Note that the email address webmaster@orangewhipstudios.com is being provided as the tag's mailTo attribute, which means that the Webmaster's email address will be inserted in place of the ERROR.mailTo reference in Listing 19.9. Figure 19.4 shows how an error message would now be shown if you were to make a coding error in one of your templates. Figure 19.4. Customized error pages help maintain your application's look and feel.To test this listing, save it as Application.cfc, not Application4.cfm. Listing 19.10. Application4.cfmUse of the <cferror> Tag in Application.cfc<!--- Filename: Application.cfc (The "Application Component") Created by: Raymond Camden (ray@camdenfamilyc.om) Purpose: Sets "constant" variables and includes consistent header ---> <cfcomponent output="false"> <cfset THIS.name = "ows23"> <cferror type="Request" template="ErrorRequest.cfm" mailto="webmaster@orangewhipstudios.com"> <cffunction name="onApplicationStart" returnType="boolean" output="false"> <!--- When did the application start? ---> <cfset APPLICATION.appStarted = now()> <cfreturn true> </cffunction> <cffunction name="onApplicationEnd" returnType="void" output="false"> <cfargument name="appScope" required="true"> <!--- Log how many minutes the application stayed alive ---> <cflog file="#THIS.name#" text= "App ended after #dateDiff('n',ARGUMENTS.appScope.appStarted,now())# minutes."> </cffunction> <cffunction name="onRequestStart" returnType="boolean" output="true"> <!--- Any variables set here can be used by all our pages ---> <cfset request.dataSource = "ows"> <cfset request.companyName = "Orange Whip Studios"> <!--- Display our Site Header at top of every page ---> <cfinclude template="SiteHeader.cfm"> <cfreturn true> </cffunction> <cffunction name="onRequestEnd" returnType="void" output="true"> <!--- Display our Site Footer at bottom of every page ---> <cfinclude template="SiteFooter.cfm"> </cffunction> </cfcomponent> Additional ERROR VariablesIn Listing 19.9, you saw how the ERROR.diagnostics variable can be used to show the user which specific error actually occurred. A number of additional variables can be used in the same way. You will see several of these used in Listing 19.11 in the next section. NOTE Note that the ERROR.generatedContent variable is not available in request error display templates. TIP These are the only variables you can use in request error display templates. You can use all types of ColdFusion variables in exception error display templates, discussed next. Creating a Customized Exception Error PageYou have seen how to create a request error display template, in which you are prevented from using any CFML tags or functions. Now you can create an exception error template, in which you can use whatever CFML tags and functions you want. For instance, Listing 19.11 is similar to Listing 19.10, but it doesn't display the ERROR.diagnostics message to the user. This means that the user won't know which type of error actually occurred. After all, your users might not care about the specifics, and you might not want them to see the actual error message in the first place. In addition, instead of allowing the user to send an email message to the Webmaster, this template has ColdFusion send an email message to the Webmaster automatically, via the <cfmail> tag. Now all you have to do is add a second <cferror> tag to your Application.cfc file, this time specifying type="Exception" and template="ErrorException.cfm". You should put this <cferror> tag right after the first one, so the first one can execute if some problem occurs with your exception error display template. Since this modification is so simple, it won't be listed in the chapter. It is included in the CD with the name Application5.cfc. Listing 19.11. ErrorException.cfmSending an Email When an Error Occurs<!--- Filename: ErrorException.cfm Created by: Nate Weiss (NMW) Please Note Included via <CFERROR> in Application.cfc ---> <html> <head><title>Error</title></head> <body> <!--- Display sarcastic message to poor user ---> <h2>Who Knew?</h2> <P>We are very sorry, but a technical problem prevents us from showing you what you are looking for. Unfortunately, these things happen from time to time, even though we have only the most top-notch people on our technical staff. Perhaps all of our programmers need a raise, or more vacation time. As always, there is also the very real possibility that SPACE ALIENS (or our rivals at Miramax Studios) have sabotaged our website.<br> <p>That said, we will naturally try to correct this problem as soon as we possibly can. Please try again shortly. Thank you.<br> <!--- Maybe the company logo will make them feel better ---> <img src="/books/2/448/1/html/2/../images/logo_b.gif" width="73" height="73" alt="" border="0"> <!--- Send an email message to site administrator ---> <!--- (or whatever address provided to <cferror>) ---> <cfif ERROR.mailTo neq ""> <cfmail to="#ERROR.mailTo#" from="errorsender@orangewhipstudios.com" subject="Error on Page #ERROR.Template#"> Error Date/Time: #ERROR.dateTime# User's Browser: #ERROR.browser# URL Parameters: #ERROR.queryString# Previous Page: #ERROR.HTTPReferer# ------------------------------------ #ERROR.diagnostics# </cfmail> </cfif> NOTE Because sending automated error emails is a great way to show how exception templates can be used, the <cfmail> tag has been introduced a bit ahead of time here. Its use in Listing 19.11 should be self-explanatory: The ColdFusion server sends a simple email message to the Webmaster. The email will contain the error message, date, browser version, and so on because of the ERROR variables referred to between the opening and closing <cfmail> tags.
See Chapter 27, "Interacting with Email," for details. TIP The Webmaster could also look in ColdFusion's logs to see any errors that might be occurring throughout the application.
See Chapter 17, "Debugging and Troubleshooting," for details. Creating a Customized Validation Error PageNow, your application responds in a friendly and consistent manner, even when problems occur in your code. The Web application framework also allows you to customize the page that appears if a user's form input doesn't comply with the validation rules you have set up using the hidden form fields technique (as described in Chapter 13, "Form Data Validation"). To create your own validation error display template, follow the same steps you performed to create your request template (see the section "Creating a Customized Request Error Page," earlier in this chapter). The only differences are that you use the special ERROR variables listed in Table 19.7 instead of those in Table 19.6, and that you should specify type="Validation" in the <cferror> tag you include in your Application.cfc file.
Listing 19.12 shows a completed validation error display template. Figure 19.5 shows how it would look to end users, if they were to submit a form without filling it out correctly. Figure 19.5. A customized display template makes it less jarring for users who fail to fill out a form correctly.As before, since the modification to the Application.cfc file was so simple, it is not listed here but included in the CD as Application6.cfc. Listing 19.12. ErrorValidation.cfmCustomizing the Display of Form Validation Messages<!--- Filename: ErrorValidation.cfm Created by: Nate Weiss (NMW) Please Note Included via <CFERROR> in Application.cfc ---> <html> <head><title>Form Fields Missing or Incomplete</title></head> <body> <!--- Introductory Message ---> <img src="/books/2/448/1/html/2/../images/logo_b.gif" width="73" height="73" alt="" align="absmiddle" border="0"> <font size="4">Please take a moment...</font><br clear="all"> Maybe it's because we are in the entertainment business and thus have lost touch with the kinds of problems that ordinary people have, but we can't quite figure out how to deal with the information you just provided. Here are the "problems" that we need you to correct: <!--- Display actual form-field problems ---> #ERROR.invalidFields# <!--- Link back to previous page ---> <p>Please <a href="javascript:history.back()">return to the form</a> and correct these minor problems.<br> Or, just use your browser's Back button.<br> </body> </html> Using the OnError MethodAs we discussed earlier in the chapter, the Application.cfc contains a set of special methods that are executed depending on certain situations. We demonstrated how the onApplicationStart and onApplicationEnd methods are executed automatically based on the life of the ColdFusion application. One more special method is the onError method. As you can probably guess, this method is called whenever an exception occurs. Unlike the <cferror> tag, which is tied to a specific error type or exception, the onError method will fire on any error. So how can you use this method? The method could do many of the things demonstrated in the listings we've already covered. You can mail the error to the administrator, or log the error to a file or database. You can even display a message to the user, but remember that the onError method will be run for any error. So for example, if your onApplicationEnd method throws an error, the onError method will run. The output won't be displayed, obviously, since no one is there to actually see it. Another option to consider when using the onError method is to use it to handle the non-visual portions of the error (emailing the administrator, logging, etc.), and use the <cfthrow> tag to let your <cferror> tags take over. The <cfthrow> tag is discussed in Chapter 32. Think of the onError method as simply taking care of the error temporarily, and then passing it back to ColdFusion. If you have already created your request, exception, and validation templates, this approach lets you continue using those templates, while adding a bit of extra functionality to your application. Listing 19.13 demonstrates the latest version of our Application.cfc file, this time with an onError method. If you save this template, be sure to save it as Application.cfc, not Application7.cfc. Listing 19.13. Application7.cfcWorking with onError<!--- Filename: Application.cfc (The "Application Component") Created by: Raymond Camden (ray@camdenfamilyc.om) Purpose: Sets "constant" variables and includes consistent header ---> <cfcomponent output="false"> <cfset THIS.name = "ows23"> <cferror type="Request" template="ErrorRequest.cfm" mailto="webmaster@orangewhipstudios.com"> <cferror type="Exception" template="ErrorException.cfm" mailto="webmaster@orangewhipstudios.com"> <cferror type="Validation" template="ErrorValidation.cfm" mailto="webmaster@orangewhipstudios.com"> <cffunction name="onApplicationStart" returnType="boolean" output="false"> <!--- When did the application start? ---> <cfset APPLICATION.appStarted = now()> <cfreturn true> </cffunction> <cffunction name="onApplicationEnd" returnType="void" output="false"> <cfargument name="appScope" required="true"> <!--- Log how many minutes the application stayed alive ---> <cflog file="#THIS.name#" text= "App ended after #dateDiff('n',ARGUMENTS.appScope.appStarted,now())# minutes."> </cffunction> <cffunction name="onRequestStart" returnType="boolean" output="true"> <!--- Any variables set here can be used by all our pages ---> <cfset request.dataSource = "ows"> <cfset request.companyName = "Orange Whip Studios"> <!--- Display our Site Header at top of every page ---> <cfinclude template="SiteHeader.cfm"> <cfreturn true> </cffunction> <cffunction name="onRequestEnd" returnType="void" output="true"> <!--- Display our Site Footer at bottom of every page ---> <cfinclude template="SiteFooter.cfm"> </cffunction> <cffunction name="onError" returnType="void" output="false"> <cfargument name="exception" required="true"> <cfargument name="eventName" type="string" required="true"> <!--- Use the cflog tag to record info on the error ---> <cfif arguments.eventName is ""> <cflog file="#THIS.name#" type="error" text="#arguments.exception.message#"> <cfelse> <cflog file="#THIS.name#" type="error" text="Error in Method [#arguments.eventName#] #arguments.exception.message#"> </cfif> <!--- Let the <cferror> tags do their job. ---> <cfthrow object="#arguments.exception#"> </cffunction> </cfcomponent> The only thing new in this template is the onError method at the end, so we'll focus on that portion. The onError method is automatically passed two arguments. The first is the exception itself. This is just like the ERROR struct discussed earlier. It has the same values and we can use it to email, log to a file, or anything else. The second argument passed to the method is the name of the event that was running when the exception occurred. This argument will only have a value when the error occurs within the Application.cfc file itself. So for example, if the onApplicationStart method threw an error, that method name would be passed to the onError method. The onError method in listing 19.14 checks to see if an eventName argument has a value. If it doesn't, it simply logs the error. Note that it uses the same file value as the onApplicationEnd's <cflog> tag. The value passed to the log is just the exception message. If the eventName argument wasn't blank, the text passed to the log is modified slightly to contain the event name as well. Lastly, we use the <cfthrow> tag to pass the error back out again from the onError method. Don't worry too much about this tag now; it's covered later in Chapter 32. Just consider the onError method here as being part of a "chain" of code blocks that will handle the error. NOTE ColdFusion also provides the <cftry> and <cfcatch> tags, which allow you to trap specific errors and respond to or recover from them as appropriate. See Chapter 32, "Error Handling," for details. |