Macromedia Coldfusion MX 7 Web Application Construction Kit

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.

Table 23.3 describes the various parts of a component definition file.

Table 23.3. The Parts of a Component

PART

DESCRIPTION

<cfcomponent> block

Surrounds everything else in the CFC file. Place an opening <cfcomponent> tag at the top of your .cfc file, and a closing tag at the bottom.

<cffunction> blocks

Within the <cfcomponent> tag, use <cffunction> blocks to create each of the component's methods. There are a few additional attributes in the <cffunction> tag for CFCs, but for the most part, you write these functions the same way you learned in 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 Table 23.4).

Table 23.4. <cfcomponent> Tag Syntax

ATTRIBUTE

DESCRIPTION

hint

What your component does, in plain English (or whatever language you choose, of course). I recommend that you provide this attribute.

displayName

An alternative, friendlier phrasing of the component's name. Make the component's actual name (that is, the filename) as self-describing as possible, rather than relying on the displayName to make its purpose clear.

If you provide these optional attributes, ColdFusion and Dreamweaver can automatically show hint and displayName in various places, to make life easier for you and the other developers who might be using the component. See the "Exploring CFCs in Dreamweaver" section, later in this chapter, for more on where you will see this information displayed.

NOTE

You can also use the extends attribute to make CFCs that inherit methods from other CFCs. For a discussion of CFC inheritance, see Advanced Macromedia ColdFusion MX 7 Application Development.

NOTE

As you will soon see, the <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 Table 23.5 and Table 23.6.

Table 23.5. <cffunction> Syntax for CFC Methods

ATTRIBUTE

DESCRIPTION

name

Required. The name of the function (method), as discussed 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 Table 23.4).

returnType

Optional. The type of data that the function returns (for instance, a date or a string). You aren't required to specify the returnType, but I recommend it. If you do, the return type will be conveniently displayed in Dreamweaver MX and by ColdFusion itself, making it a lot easier to keep track of which methods do what. Also, the returnType is required if you want the method you're creating to be available as a Web Service.

access

Optional. This attribute defines how your method can be used. If access="remote", the method can be accessed over the Internet as a Web Service, by Web browsers, or by the Flash Player. If access="public", the method can be used internally by any of your ColdFusion pages (similar to a UDF or custom tag), but not by Flash, browsers, or Web Services. If access="private", the method can only be used internally by other methods in the same component. If access="package", the method can only be used internally by other methods in the same component, or other components in the same directory.

roles

Optional. A list of security roles or user groups that should be able to use the method. This attribute only has meaning if you are using the <cflogin> security framework discussed in 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.

Table 23.6. <cfargument> Syntax for CFC Method Arguments

ATTRIBUTE

SYNTAX

name

Required. The name of the argument, as discussed in Chapter 22.

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 Table 23.4).

type

Optional. The data type of the argument, as discussed in Chapter 22. You can use any of the values mentioned in the note under Table 23.5 except for void.

required

Optional. Whether the argument is required. See 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

<!--- 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>

NOTE

Earlier, I explained that there are two types of components: static components, which just provide functionality, and instance-based components, which provide functionality but also hold information. This CFC is an example of a static component. You will see how to create instance-based components shortly.

This version of the CFC only has one method, called listFilms(), which queries the database for a listing of current films. The query object is returned as the method's return value (this is why returnType="query" is used in the method's <cffunction> tag).

The listFilms() method takes one optional argument called searchString. If the searchString argument is provided, a WHERE clause is added to the database query so that only films with matching titles or summaries are selected. If the searchString isn't provided, all films are retrieved from the database and returned by the new method.

As you can see, building a simple component isn't much different from creating a user-defined function. Now that you've created the component, let's take a look at how to use it in your ColdFusion code.

TIP

You can use the Create Component dialog in Dreamweaver MX to create the basic skeleton of <cfcomponent>, <cffunction>, <cfargument>, and <cfreturn> tags. Then all you need to do is add the appropriate logic to the <cffunction> blocks. See the "Using the Create Component Dialog" section, later in this chapter.

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.

In general, you will probably use the <cfinvoke> syntax for static components (like the FilmSearchCFC), and the <cfscript> syntax when interacting with a specific instance of a component. See "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 Listing 23.17, you can either add additional attributes to <cfinvoke> or you can nest a <cfinvokeargument> tag within the <cfinvoke> tag. Table 23.7 and Table 23.8 show the attributes supported by <cfinvoke> and <cfinvokeargument>.

Table 23.7. <cfinvoke> Tag Syntax

ATTRIBUTE

DESCRIPTION

component

The name of the component, as a string (the name of the file in which you saved the component, without the .cfc extension) or a component instance.

method

The name of the method you want to use.

returnVariable

A variable name in which to store whatever value the method decides to return.

(method arguments)

In addition to the component, method, and returnVariable attributes, you can also provide values to the method's arguments by providing them as attributes. For instance, the listFilms() method from Listing 23.17 has an optional argument called SearchString. To provide a value to this argument, you could use searchString="Saints" or SearchString="#FORM.keywords#". You can also provide arguments using the separate <cfinvokeargument> tag (see Table 23.8).

argumentCollection

Optional, and for special cases only. This attribute lets you provide values for the method's arguments together in a single structure. It works the same way as the attributeCollection attribute of the <cfmodule> tag (see "Introducing the <cfmodule> Tag," earlier in this chapter).

Table 23.8. <cfinvokeargument> Tag Syntax

ATTRIBUTE

DESCRIPTION

name

The name of the argument. So, to provide a value to an argument called searchString, you could use a <cfinvokeargument> tag with name="searchString".

value

The value of the argument. To provide the value of a form field to the searchString argument, you could use value="#FORM.searchString#".

NOTE

For the component attribute, you can use the component name alone (that is, the file without the .cfc extension) if the .cfc file is in the same folder as the file that is using the <cfinvoke> tag. You can also specify a .cfc in another folder, using dot notation to specify the location of the folder relative to the Web server root, where the dots represent folder names. For instance, you could use the FilmSearchCFC component by specifying component="ows.20.FilmSearchCFC". For more information, see the ColdFusion MX documentation.

NOTE

You can also save .cfc files in the special CustomTags folder or its subfolders. For the COMPONENT attribute of <cfinvoke>, specify the location relative to the CustomTags folder, again using dots to separate the folder names. This is the same way that you can specify folder locations for the name attribute of the <cfmodule> tag. See the "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

<!--- Filename: UsingFilmSearchCFC1.cfm Author: Nate Weiss (NMW) Purpose: Uses the FilmSearchCFC component to display a list of films ---> <html> <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>

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.

Figure 23.7. It's easy to execute a component's methods and use the results.

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>

<!--- Filename: UsingFilmSearchCFC2.cfm Author: Nate Weiss (NMW) Purpose: Uses the FilmSearchCFC component to display a list of films ---> <html> <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>

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).

Figure 23.8. The <CFINVOKE> tag makes it easy to pass values to methods.

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.

Table 23.9 shows the attributes you supply to the <cfobject> tag to create an instance of a CFC.

Table 23.9. <cfobject> Tag Syntax for CFC Instantiation

ATTRIBUTE

DESCRIPTION

component

Required. The name of the component (that is, the CFC filename without the .cfc extension).

name

Required. A variable name in which to store the CFC instance. After the <cfobject> tag executes, your code can refer to the variable named here to interact with the instance.

NOTE

You can use the <cfobject> tag to create instances of other types of objects, not just CFCs. For instance, it can create instances of JavaBeans and Windows COM controls. Only the attributes relevant for CFCs are included in Table 23.9. For information on the other uses of <cfobject>, see 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 ---> <html> <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:

<cfset filmsQuery = myFilmSearcher.listFilms()>

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.

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 ---> <html> <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:

<cfset myFilmSearcher = createObject("component","filmSearchCFC1")>

Neither <cfobject> nor createObject() is better. Just use whichever one you prefer.

Категории