With the introduction of ColdFusion Application Server 3 Allaire added a powerful new feature to the core ColdFusion language: custom tags. This feature has been carried forward to the current version of ColdFusion Server version 4.5. Custom tags allow developers to create portable and powerful extensions to the language. By building a “black box” architecture developers are able to create modular, powerful extensions that could be shared not only with other developers on a project but across the Internet as well.
In this chapter we will discuss the basic architecture of custom tags. You will create a simple custom tag and enhance it into a full-featured secure ColdFusion custom tag. You will also learn about custom tag enhancements specific to the Coldfusion 4 and 4.5 Server.
Understanding Custom Tag Basics
Two basic aspects of using custom tags need to be undestood considering the details of custom tag development:
• Referencing custom tags
• Seeping custom tags
Referencing Custom Tags
There are two types of custom tags: those developed using the ColdFusion language and those developed using external programming languages such as Visual C++. The latter are generally known as CFX tags
To reference these tags in normal CFML, you use a special notation
tF _TagName Tags developed using standard ColdFusion
CFX_TagName Custom CFX tags written in Visual C++ and similar languages
For instance, a custom tag called Email Check would be referred to in CFML as CF_Email Check. This in turn tells the ColdFusion Application Server to look for a file named Email Check. cfm. Here is an example:
Here you see standard CFML (the CFSET)followed by a call to the custom tag. Custom tags take attributes just as most CFML tags do. The only difference is that as the developer of the custom tag, you are left to decide which attributes your tag will use. This will change depending on the particular function of your custom tag.
When you call a custom tag, the server will attempt to find a.corresponding CFM file for the tag. It will first check the same directory as the calling template. So, if the CFM file calling the custom tag is in the folder the server will first check that folder. If you build a custom tag that is useful for only a particular project you would typically place the custom tag in the same folder.
The other option is to use the custom tags folder. If you installed ColdFusion on your C drive, this would be the c: \cfusi on\customtags folder. The advantrzs of using this folder is that any CFM template on the server can use the tag. If the server cannot find the custom tag in the same directory or in the root custom tags folder, the server will then begin searching any subdirectories under the custom tags folder. It is important to remember that if you have a template with the same name as your custom tag in both the server’s custom tags folder and in the same folder as the template that called the tag the server will give precedence to the file in the same folder.
It is for exactly these reasons that Allaire created the CFMOqULEtag. Using CFMODULE enables you to gain precise control over which custom tag template will be used by the server. The general syntax of CFMODULloEoks like this:
This instance of CFMODULteElls the server to call Email Check.cfm.This is the same as this syntax:
The benefit of using CFMODULisEthat you know exactly which custom tag is going to be used. The CFMODULtaEg has other features that help it to be used for including custom tags (see Chapter 8).
Scoping Custom Tags
The second important feature of custom tags is that they exist in their own scope, or environment. Think of this as part of the black box nature of custom tags. By this we mean that information is passed to and from custom tags but data created within the tag does not ‘overwrite information outside of the tag. This is important. If not for this feature a custom tag could accidentally overwrite a variable in the document that called it
For example, if the calling template has a variable named Tempand the custom tag has the code <CFSET Temp – ·My.NewVa 1ue’ >. the value of TEMP in the calling document would be lostltthe calling ~plate’ and the custom tag did not have separate scopes.
By using a separate scope for custom tags, you can be sure that data will not be corrupted. Hence the black box term. Imagine a custom tag as a black box. You send it data. The custom tag does its work. The custom tag then sends the information back to the calling template. You don’t know and don’t care what happens inside the black box (the custom tag) as long as what you get back is what you want.
Scoping is handled within custom tags by using the Attri butes and Call e r prefixes. Any data sent to ~ custom tag can be referenced within the Att ri butes scope. Using the preceding example, <CF_Emai1 Check Email •.••#.TEST#·>.1the variable Attri butes. Test will be available within the Ema;1Check custom tag. To send informationfrom the custom tag to the calling template, you simply use the Call e r scope. The following line will set ‘a variable in the calling template: <CFSET Call e r .Val i dEma;1 = •Yes •>.You reference that value in the calling template without the Call e r scope. Any CFML in the calling template after the use of the custom tag can then refer to the variable as Val; dEmai1, not Call er .Val i dEmai1.
We have discussed the ways that custom tags are called via templates, so let’s jump in .now with an example. Pretend that you have a simple application that enables a visitor to enter three numbers. After hitting the Submit button, the visitor theri sees the result of multiplying all three numbers. Listing 31.1 shows this application.
<CFPARAM NAME-·Form.Numberl· oOEFAULT-o>
<CFPARAM NAME~·Form.Number2· DEFAULT-o>
<CFPARAM NAME-·Form.Number3· DEFAULT-O>
<CFIF IsDefined(·Form.Fieldnames·» °
<CFSET RESULT – Val(Form.Numberl) * Val(Form.Number2) * Val(Form.Number3»
<CFQUTPUT>The result of your multiplication of #Val(Form.Numberl)#,
IVal(Fonn.Number2)#, and #Val(Form.Number3). ;s #RESULT#</CFOUTPUT>
<TO><INPUT TYPE-‘text’ NAME-‘Numberl’ SIZE-3 VALUEft·#Val(Form.Numberl)’·></TD>
<TD><INPUT TYPE-‘text~ NAME-‘Number2’ SIZE-3 VALUE-·’Val(Fonn.Number2)’·></TD>
<TO><INPUT TYPE-‘text’ NAME-” Number3′ SIZE-3 VALUE-·’Val(Fonn.Number3)’·></TD>
<TO COLSPAN-2><INPUT TYPE-‘Submit’ VALUE-‘Display Result’></TO>
This application is simple so we won’t spend a lot of time discussing it. You have a. form that asks the user to enter three numbers, and after the user hits the Submit button, the form calls itself and displays the results. You do a minor bit of error checking by wrapping each of the form variables with the Val command. This ensures that you don’t try to multiply a number by a letter.
Let’s take this application a step further. Pretend that you work for a company whose sole purpose is to provide multiplication services to its clients. You work 24/7, year round to take clients’ numbers and return the product. It right be useful, then, to create a custom tag that would do some of the grunt work for you. If you could create a custom tag that would do the multiplication, you could then spend more time worrying about the look and feel of the application
As you can see you told the server to look for a custom tag called Mu1ti ply, cfm. Agclm the server knows to look for this file because of the use of CF_ * syntax. In this case your code reads:
How do you name the custom tag, and how do you come up with NUM1 NUM2 and NUM3?Pure random choice. You can choose not only any name for a custom tag but also the attributes to send. Of course it makes sense to name your custom tag after its function. That is why the tag is named Multi ply. By the same token it makes sense to give your attributes sensible names. In this case your custom tag is going to take three numbers and multiply them so you choose NUM1 NUM2 and NUM3 for simplicity’s sake. Before you go any further, try running the template as it stands. After you have copied the file from the CD, run it, enter some numbers and hit the Display Result button. (Be sure you have not copied the file multi ply, cfm from.the CD to your custom tags directory yet.)
Notice the error message? It is shown in Figure 31.1
The Cold Fusion server gave you an error because you have not created Multiply cfm yet. You should also notice that the error states that the file could not be found in the tree of.installed custom tags. This simply reflects that you can store custom tags either in the same directory as the calling template or in the root server’s custom tag folder.
Now that you have seen how ColdFusion throws an error for a missing custom tag you can create your custom tag. Listing 31.3 shows the code of your custom tag
Created —> ‘
••••• ~ 4 ., ..•._ .1 .._.•..~<,> •• ,
: Multiplies three numbers and returns the product. ,
: February 2’.2000 ‘
-<!— Recreate our attributes as local variables —>
<CFSET’NUMl – Val(Attributes.NUM1»
<CFSET NUM2 – Val(Aftributes.NUM2»
<CFSET NUM3 – Val(Attributes.NUM3»
<1— Create the result —>
<CFSET RESULT – NUMl ~”NUM2 * NUM3>
<!— Return the result to the template —>
<CFSET Caller.Result – RESULT>
Let’s examine this template line by line. You begin by renaming the attributes that
were sent to the tag: .
<CFSET NUM1 – Val(Attributes.NUM1»
(CFSET NUM2 – Val(Attributes.NUM2»
<CFSET NUM3 – Val(Attributes:NUM3»
The renaming is completely unnecessary, but you do it to make your code a bit easier to reread. You could just as easily refer to Attributes. NUM1 in your code, but renaming the variable to NUM1 means that later you get to type a bit l~in your code. As an extra check, you use the Va1 command to ensure that you don’t try to multiply non-numeric values.
The next line of code, <CFSET RESULT- NUMl* NUM2* NUM3>, creates your result. This isn’t rocket science; you are basically using the same code you cut out of the original document.
Finally, you use the Ca11e r scope to return the value to the calling document. The line <CFSETCa11e r . Resu 1t – ·RESULT>ensures that your calling document can refer to the Resu1 t variable. You can see the variable being used in this line from Listing 31.2
<CFOUTPUT>The result of your multiplication of #Val(Form.Numberl)##Val(Form.Number2)#and #Val(Form.Number3)# is #RESULT#</CFOUTPUT>
Notice how you don’t need to use Caller .Result, even though that was the name you used in your custom tag. Remember that the custom tag lives in its own scope. When the custom tag set Call er . Result this created a new variable in your program called Result;
Rim the program again and you will see that the error message has gone away. You will also notice that, functionality-wise, your template acts the same as it did before. But you have created something much more advanced. Now, to share your code with other developers, all you would need to do is copy mu1ti ply. cfm into the ColdFusion custom tags folder. Even better, if for some reason the laws of mathematics changed so that every multiplication must also include a subtraction by 3.14159, you could easily add this new rule to your file. Atthat point; evert application that uses the custom tag would be instantly updated.