Your First CFC
The best news about CFCs is that there is really very little to learn about them. For the most part, you just write functions in much the same way that you learned in Chapter 22. You then save them in a special file and surround them with a <cfcomponent> tag. That's really about it.Let's take a closer look.
The Structure of a CFC File
Each ColdFusion component is saved in its own file, with a .cfc extension. Except for one new tag, <cfcomponent>, everything in the file is ordinary CFML code. With the .cfc extension instead of .cfm, the ColdFusion server can easily detect which files represent CFC components.Chapter 22. Within each <cffunction> tag, you will use <cfargument> to define the method's arguments, <cfreturn> to return whatever result you want the method to return, and so on.
Initialization code | Any CFML code that is inside the <cfcomponent> block but not within any of the <cffunction> tags will execute the first time an instance of the component is used. I call this initialization code because the main reason you would want code to run when the CFC is first created would be to set values in the THIS (or VARIABLES) scope to their initial values. |
Introducing the <cfcomponent> Tag
The <cfcomponent> tag doesn't have any required attributes, so in its simplest use, you can just wrap opening and closing <cfcomponent> tags around everything else your CFC file contains (mainly <cffunction> blocks). That said, you can use two optional attributes, hint and displayName, to make your CFC file more self-describing (see Exploring CFCs in Dreamweaver" section, later in this chapter, for more on where you will see this information displayed.<cffunction> and <cfargument> tags also have hint and displayName attributes. Each aspect of a CFC that someone would need to know about to actually use it can be described more completely within the component code itself.
Using <cffunction> to Create Methods
The biggest part of a CFC is the ColdFusion code you write for each of the CFC's methods. (Remember, I use the word method to refer to a function attached to a CFC). To create a component's methods, you use the <cffunction> tag in much the same way you learned in Chapter 22. If the method has any required or optional arguments, you use the <cfargument> tag, again as shown in Chapter 22.The <cffunction> and <cfargument> tags each take a few additional attributes that Chapter 22 didn't discuss because they are only relevant for CFCs. The most important new attributes are hint and displayName, which all the CFC-related tags have in common. A summary of all <cffunction> and <cfargument> attributes is provided in Chapter 22.
hint | Optional. A description of the method. Like the hint attribute for <cfcomponent>, this description will be visible in Dreamweaver MX to make life easier for you and other developers. It is also included in the automatic documentation that ColdFusion produces for your components. |
displayName | Optional. Like the displayName attribute for <cfcomponent> (see Chapter 21, "Securing Your Applications." If a roles attribute is provided, and the current user has not logged in as a member of one of the allowed roles, they won't be able to access the method. The effect is similar to using the isUserInRole() function to deny access within normal ColdFusion pages, as discussed in Chapter 21. Note The roles attribute for a CFC method lists a set of roles. If the user is in one of those roles, they can call the method. The isUserInRole() function, however, uses a list of roles the user must exist in. In other words, the user can be in any role when using the roles attribute, but must be in all the roles when using isUserInRole(). For details about this attribute, see our companion book, Advanced ColdFusion MX Application Development. |
hint | An explanation of the argument's purpose. Like the HINT attribute for <cfcomponent> and <cffunction>, this description will be visible in Dreamweaver MX to make life easier for you and other developers. It is also included in the automatic documentation that ColdFusion produces for your components. |
displayName | Optional. Like the displayName attribute for <cfcomponent> (see Chapter 22. You can use any of the values mentioned in the note under Chapter 22 for details. |
default | Optional. A default value for the argument, if required="No". See Chapter 22. |
NOTE
The valid data types you can provide for returnType are: any, array, binary, Boolean, date, guid, numeric, query, string, struct, uuid, variableName, and xml. If the method isn't going to return a value at all, use returnType="void". If the method is going to return an instance of another component, you can provide that component's name (the filename without the .cfc) as the returnType.
NOTE
There is actually another CFC-related tag, called <cfproperty>. In this version of ColdFusion the <cfproperty> tag doesn't affect how a CFC works; it only helps the CFC be more self-documenting, mainly for the benefit of Web Services. See the "Documenting Properties With <cfproperty>" section, near the end of this chapter.
A Simple Example
Let's look at a simple example of CFC. Say you want to create a CFC called FilmSearchCFC, which provides a simplified way to search for films. You like the idea of being able to reuse this component within your ColdFusion pages, instead of having to write queries over and over again. You'd also like to be able to flip a switch and have the component available to the Flash Player or Web Services.Listing 23.17 is a simple version of the FilmSearchCFC.
Listing 23.17. FilmSearchCFC.cfcA Simple CFC
Using the Create Component Dialog" section, later in this chapter.
<!---
Filename: FilmSearchCFC.cfc
Author: Nate Weiss (NMW)
Purpose: Creates FilmSearchCFC, a simple ColdFusion Component
--->
<!--- The <CFCOMPONENT> block defines the CFC --->
<!--- The filename of this file determines the CFC's name --->
<cfcomponent output="false">
<!--- ListFilms() method --->
<cffunction name="listFilms" returnType="query" output="false">
<!--- Optional SearchString argument --->
<cfargument name="searchString" required="no" default=">
<!--- var scoped variables --->
<cfset var getFilms = ">
<!--- Run the query --->
<cfquery name="getFilms" datasource="ows">
SELECT FilmID, MovieTitle FROM Films
<!--- If a search string has been specified --->
<cfif ARGUMENTS.searchString neq ">
WHERE (MovieTitle LIKE '%#ARGUMENTS.searchString#%'
OR Summary LIKE '%#ARGUMENTS.searchString#%')
</cfif>
ORDER BY MovieTitle
</cfquery>
<!--- Return the query results --->
<cfreturn getFilms>
</cffunction>
</cfcomponent>
Using the CFC in ColdFusion Pages
Once you have completed your CFC file, there are two basic ways to use the new component's methods in your ColdFusion code:
- With the <cfinvoke> tag, as discussed next.
- With <cfscript> syntax, in the form component.methodName(). To use this syntax, you must first create an instance of the CFC with the <cfobject> tag or the createObject() function.
The Two Types of Components," earlier in this chapter.
Calling Methods with <cfinvoke>
The most straightforward way to call a CFC method is with the <cfinvoke> tag. <cfinvoke> makes your CFC look a lot like a custom tag. To provide values to the method's arguments, as in the optional searchString argument in Introducing the <cfmodule> Tag," earlier in this chapter).Using Dot Notation to Avoid Conflicts" section, earlier in this chapter. You can also start the component attribute with a mapping from the Mappings page of the ColdFusion Administrator.Listing 23.18 shows how to use <cfinvoke> to call the listFilms() method of the FilmSearchCFC component created in Listing 23.17.
Listing 23.18. UsingFilmSearchCFC1.cfmInvoking a Component Method
First, the <cfinvoke> tag invokes the LlistFilms() method provided by the FilmSearchCFC1 component. Note that the correct value to provide to component is the name of the component filename, but without the .cfc extension. When this page is visited with a browser, ColdFusion will see the <cfinvoke> tag and look for the corresponding CFC file (FilmSearchCFC.cfc). It will then execute the code in the <cffunction> block with name="listFilms".The returnVariable attribute has been set to filmQuery, which means that filmsQuery will hold whatever value the method returns. The method in question, listFilms(), returns a query object as its return value. Therefore, after the <cfinvoke> tag executes, the rest of the example can refer to filmsQuery as if it were the results of a normal <cfquery> tag. Here, a simple <cfoutput> block outputs the title of each film.The result is a simple list of film titles, as shown in Figure 23.7.
<!---
Filename: UsingFilmSearchCFC1.cfm
Author: Nate Weiss (NMW)
Purpose: Uses the FilmSearchCFC component to display a list of films
--->
&l275>
<head><title>Film Search Example</title></head>
<body>
<!--- Invoke the ListFilms() method of the FilmSearchComponent --->
<cfinvoke component="FilmSearchCFC" method="listFilms"
returnVariable="FilmsQuery">
<!--- Now output the list of films --->
<cfoutput query="filmsQuery">
#FilmsQuery.MovieTitle#<br>
</cfoutput>
</body>
</html>
Figure 23.7. It's easy to execute a component's methods and use the results.
[View full size image]

Supplying Arguments
The listFilms() method from Listing 23.17 takes an optional argument called searchString. This argument was not provided to the method in Listing 23.18, so the method will always return all films. Listing 23.19 shows how to supply values to method arguments by adding an attribute to the <cfinvoke> tag.
Listing 23.19. UsingFilmSearchCFC2.cfmSupplying Arguments with <cfinvoke>
In this example, a very simple search form has been added at the top of the page, where the user can filter the list of films by typing in a keyword. The value that the user types is passed to the searchString argument of the listFilms() method. The method responds by returning only those films that contain the user's filter string in their title or summary (Figure 23.8).
<!---
Filename: UsingFilmSearchCFC2.cfm
Author: Nate Weiss (NMW)
Purpose: Uses the FilmSearchCFC component to display a list of films
--->
&l275>
<head><title>Film Search Example</title></head>
<body>
<!--- FORM parameter called Keywords, empty by default --->
<cfparam name="FORM.keywords" default=">
<!--- Simple form to allow user to filter films --->
<cfform>
<cfinput name="keywords" value="#FORM.keywords#">
<input type="submit" value="Filter">
</cfform>
<!--- Invoke the ListFilms() method of the FilmSearchComponent --->
<!--- Pass the user's search keywords to the SearchString argument --->
<cfinvoke component="FilmSearchCFC" method="listFilms"
searchString="#FORM.keywords#"
returnVariable="filmsQuery">
<!--- Now output the list of films --->
<cfoutput query="filmsQuery">
#filmsQuery.MovieTitle#<br>
</cfoutput>
</body>
</html>
Figure 23.8. The <CFINVOKE> tag makes it easy to pass values to methods.
[View full size image]

NOTE
You can use the <cfinvokeargument> tag to supply the SearchString argument (or any other argument), instead of providing the argument as an attribute of <cfinvoke>. You can see this in action in the next example (Listing 23.20).Calling an Instance's Methods
In the last listing, you saw how to use the <cfinvoke> tag to call a CFC method. Calling methods this way isn't much different from calling a custom tag with <cfmodule>, or calling a UDF. It's also possible to create an instance of a CFC, and then call the instance's methods. If the CFC doesn't track instance data (a shopping cart, say, or information about a particular film), there isn't much of a functional difference. But it's worth taking a look at now, because it underscores the notion of a CFC as an object that provides functionality (in the form of methods).To work with methods in this way, two steps are involved:
1. | Create an instance of the CFC with the <cfobject> tag or createObject() function. |
2. | Invoke whatever methods you want, using the <cfinvoke> tag as you learned in the last section. But instead of specifying the component by name, you pass the component instance directly to the component attribute. You can repeat this part as many times as you like, using the same component instance. |
Appendix B or the companion book, Advanced ColdFusion MX Application Development.Listing 23.20 is a simple example of CFC instantiation and method calling. This listing does the same thing as the previous one, except that it calls the listFilms() method using an instance of the FilmSearchCFC1 component, rather than the component itself.
Listing 23.20. UsingFilmSearchCFC3.cfmCreating a Component Instance
<!---
Filename: UsingFilmSearchCFC3.cfm
Author: Nate Weiss (NMW)
Purpose: Uses the FilmSearchCFC component to display a list of films
--->
&l275>
<head><title>Film Search Example</title></head>
<body>
<!--- FORM parameter called Keywords, empty by default --->
<cfparam name="FORM.keywords" default=">
<!--- Simple form to allow user to filter films --->
<cfform>
<cfinput name="keywords" value="#FORM.keywords#">
<input type="submit" value="Filter">
</cfform>
<!--- Create an instance of the CFC --->
<cfobject component="FilmSearchCFC" name="myFilmSearcher">
<!--- Invoke the ListFilms() method of the CFC instance --->
<cfinvoke component="#myFilmSearcher#" method="listFilms"
returnVariable="filmsQuery">
<!--- Pass the user's search keywords to the SearchString argument --->
<cfinvokeargument name="searchString" value="#FORM.keywords#">
</cfinvoke>
<!--- Now output the list of films --->
<cfoutput query="filmsQuery">
#filmsQuery.MovieTitle#<br>
</cfoutput>
</body>
</html>
Calling Methods with <cfscript> Syntax
You've seen how you can call a component's methods using <cfinvoke>. You can also call methods using a <cfscript> syntax, where you call a CFC's methods in a way that makes them look more obviously like functions.To call methods using the <cfscript> syntax, you just use the method like a function (either a built-in CFML function or a UDF), as in a <cfset> tag. The only difference is that you precede the function name with a component instance, separated with a dot. So, if you have a object instance called myFilmSearcher, you could use this line to call its listFilms() method:
Functionally, this way of calling a method isn't any different than using <cfinvoke>, but it's more concise, so you may prefer it. Listing 23.21 is the same as the previous listing, but with the <cfinvoke> tag replaced with the script-style syntax.
<cfset filmsQuery = myFilmSearcher.listFilms()>
Listing 23.21. UsingFilmSearchCFC4.cfmCalling Methods using <cfscript> Syntax
<!---
Filename: UsingFilmSearchCFC4.cfm
Author: Nate Weiss (NMW)
Purpose: Uses the FilmSearchCFC component to display a list of films
--->
&l275>
<head><title>Film Search Example</title></head>
<body>
<!--- FORM parameter called Keywords, empty by default --->
<cfparam name="FORM.keywords" default=">
<!--- Simple form to allow user to filter films --->
<cfform>
<cfinput name="keywords" value="#FORM.keywords#">
<input type="submit" value="Filter">
</cfform>
<!--- Create an instance of the CFC --->
<cfobject component="FilmSearchCFC" name="myFilmSearcher">
<!--- Invoke the CFC's ListFilms() method --->
<cfset filmsQuery = myFilmSearcher.listFilms(FORM.keywords)>
<!--- Now output the list of films --->
<cfoutput query="filmsQuery">
#filmsQuery.MovieTitle#<br>
</cfoutput>
</body>
</html>
Instantiating Components with createObject()
The last two examples used the <cfobject> tag to create an instance of a CFC. As an alternative, you can use the createObject() function to do the same thing. Provide the word component as the function's first argument, and the name of the desired CFC as the second argument. The function will return the component instance, which you can then use to call methods.In other words, you could replace the <cfobject> tag in Listing 23.21 with this line:
Neither <cfobject> nor createObject() is better. Just use whichever one you prefer.
<cfset myFilmSearcher = createObject("component","filmSearchCFC1")>
