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 FileEach 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.
Introducing the <cfcomponent> TagThe <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).
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 MethodsThe 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.
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 ExampleLet'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 PagesOnce you have completed your CFC file, there are two basic ways to use the new component's methods in your ColdFusion code:
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>.
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 ArgumentsThe 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 MethodsIn 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:
Table 23.9 shows the attributes you supply to the <cfobject> tag to create an instance of a CFC.
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> SyntaxYou'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. |