Macromedia Coldfusion MX 7 Web Application Construction Kit

ColdFusion developers often refer to a file of conceptually related UDFs as a UDF library. Actually, there are no specific rules about what kinds of UDFs you can collect into a library, but it makes sense to group your UDFs into files according to some kind of common concept.

In fact, you have already seen a small UDF library: the FilmFunctions1.cfm file shown in Listing 22.2. It contains only one function, but you can still think of it as a library that you could expand to include other film-related functions in the future.

Designing the UDF Library

Let's say your team needs some more film-related functions added to the FilmFunctions library. Sounds like fun! You decide to create a new version of the library file, called FilmFunctions2.cfm. You sit down with the other members of your team, and come up with the list of functions shown in Table 22.4.

Table 22.4. Functions in the FilmFunctions UDF Library

FUNCTION

PURPOSE

getFilmsQuery()

This function returns a query object that contains information about films in the database. It supports one argument called filmID, which is optional. If the function is called without filmID, the function simply executes a <cfquery> that gets information about all films from the database and returns the query object. If a filmID is provided, however, the query object will only contain one row, corresponding to the specified film.

getFilmTitle()

This behaves in the same way as the getFilmTitle() function created in the first version of the library file. It takes one argument, filmID, which is the ID of the film to get the title for. Internally, this function can make use of the getFilmsQuery() function.

getFilmURL()

This function is similar to getFilmTitle(). It takes one argument, filmID. Instead of returning the film's title, however, it returns a standardized URL to a page called ShowFilm.cfm containing details about the film. The function includes the film's ID number in the URL so the ShowFilm.cfm template can display information about the correct film.

makeFilmPopupLink()

This function also accepts a filmID argument. It returns the HTML code needed to display a link for the selected film. When the link is clicked, a pop-up window appears with some basic information about the selected film. Internally, this function calls a general-purpose UDF function called JavaScriptPopupLink(), discussed later in this section.

Listing 22.4 shows the code for the new FilmFunctions2.cfm UDF library.

Listing 22.4. FilmFunctions2.cfm A UDF function library

<!--- Filename: FilmFunctions2.cfm Created by: Nate Weiss (NMW) Purpose: Creates a library of user-defined functions related to films ---> <!--- Function: getFilmsQuery() ---> <!--- Returns a query object from the Films table in the database ---> <cffunction name="getFilmsQuery" returntype="query" output="false"> <!--- Optional argument: FilmID ---> <cfargument name="filmID" type="numeric" required="No"> <!--- This variable is for this function's use only ---> <cfset var filmsQuery = ""> <!--- Query the database for information about all films ---> <!--- The query is cached to improve performance ---> <cfquery name="filmsQuery" datasource="ows" cachedwithin="#createTimespan(0,1,0,0)#"> SELECT * FROM Films <!--- If a FilmID argument was provided, select that film only ---> <cfif isDefined("ARGUMENTS.filmID")> WHERE FilmID = #ARGUMENTS.filmID# <!--- Otherwise, get information for all films, in alphabetical order ---> <cfelse> ORDER BY MovieTitle </cfif> </cfquery> <!--- Return the query ---> <cfreturn filmsQuery> </cffunction> <!--- Function: getFilmTitle() ---> <!--- Returns the title of a film, based on FilmID ---> <cffunction name="getFilmTitle" returnType="string" output="false"> <!--- One argument: FilmID ---> <cfargument name="filmID" type="numeric" required="Yes"> <!--- This variable is for this function's use only ---> <cfset var getFilm = ""> <!--- Get a query object of all films in the database ---> <cfset getFilm = getFilmsQuery(ARGUMENTS.filmID)> <!--- Return the film's title ---> <cfreturn getFilm.MovieTitle> </cffunction> <!--- Function: getFilmURL() ---> <!--- Returns the URL to a film's detail page, based on FilmID ---> <cffunction name="getFilmURL" returnType="string" output="false"> <!--- One argument: FilmID ---> <cfargument name="filmID" type="numeric" required="Yes"> <!--- Return the appropriate URL ---> <cfreturn "ShowFilm.cfm?FilmID=#ARGUMENTS.filmID#"> </cffunction> <!--- Include another UDF function library ---> <!--- This one creates the JavaScriptPopupLink() function ---> <cfinclude template="SimpleJavaScriptFunctions.cfm"> <!--- Function: MakeFilmPopupLink() ---> <!--- Returns an HTML link for a film, based on FilmID ---> <cffunction name="MakeFilmPopupLink" returnType="string" output="false"> <!--- One argument: FilmID ---> <cfargument name="filmID" type="numeric" required="Yes"> <!--- Return a link for the film ---> <cfreturn javaScriptPopupLink(getFilmURL(ARGUMENTS.filmID), getFilmTitle(ARGUMENTS.FilmID))> </cffunction>

Each of the <cffunction> blocks in Listing 22.4 is fairly simple. It's interesting to note here that UDFs can call other UDFs in the same file. They can even call functions in other files, as long as the <cfinclude> tag has been used to include the other files.

NOTE

In fact, UDF A can always call UDF B, as long as you've included UDF B in one of the ColdFusion files involved in the page request. It doesn't matter if some of the files are turn included by other files, or deeply the files are included within each other. The order of inclusion doesn't matter either.

Let's take a closer look at each one of these new UDFs individually:

  • For the getFilmsQuery(), note that the <cfargument> tag includes a required="No" attribute, which means the argument is optional. The first thing this function does is execute a <cfquery> tag film information from the database. Within the query, a simple isDefined("ARGUMENTS.filmID") test is used to find out whether the optional filmID argument has been provided when the function is actually used. If so, a WHERE clause is dynamically included in the SQL statement (so the query retrieves just the information about the specified film).

  • The getFilmTitle() function has been reworked a bit, mainly to demonstrate that UDFs can call any other UDFs in the same file. Now, instead of using a <cfquery> tag within the body of the function, the new, convenient getFilmsQuery() function is used instead. Note that the filmID argument provided to getFilmTitle() is in turn passed to getFilmsQuery() internally, which means that the returned query contains data about the specified film only. It is then a simple matter to return the film's title using the <cfreturn> tag.

  • The getFilmURL() function is the simplest of all the UDFs in this library. It just returns a URL that points to a template called ShowFilm.cfm, passing along the specified filmID as a URL parameter. The nice thing about this function is that it abstracts the idea of a film's Detail Page. If the URL that people should go to for more information about a film changes in the future, you can just edit the function in one place, rather than in multiple places throughout the application.

  • The makeFilmPopupLink() function is interesting because it calls three functions internally. It uses both getFilmURL() and getFilmTitle() to get the URL and title of the specified film, respectively. It then passes the returned values to the javaScriptPopupLink() function, created in a separate UDF library file called SimpleJavaScriptFunctions.cfm. You will see the code for this function in a moment. For now, just take it on faith that the function returns the HTML and JavaScript code needed to create a link that opens a pop-up window.

Putting the UDF Library to Use

Listing 22.5 shows a new version of the Film List page (see Listings 22.1 and 22.3 for the previous versions). This version gets its work done with just a few lines of code, and it's more functional, too! Now, when the user clicks a film's title, a small pop-up window displays more information about that film (Figure 22.2).

Listing 22.5. FilmList3.cfm Using several UDFs together

<!--- Filename: FilmList3.cfm Created by: Nate Weiss (NMW) Purpose: Displays a list of films ---> <!--- Include the set of film-related user-defined functions ---> <cfinclude template="FilmFunctions2.cfm"> <!--- Get a query object about films in database ---> <cfset getFilms = getFilmsQuery()> <html> <head><title>Film List</title></head> <body> <h3>Here is the current list of Orange Whip Studios films:</h3> <!--- Now it is extremely easy to display a list of film links ---> <cfoutput query="getFilms"> #makeFilmPopupLink(getFilms.FilmID)#<br> </cfoutput> </body> </html>

First, a <cfinclude> tag is used to include the new library of film-related UDFs. That makes it possible to call the getFilmsQuery() function to get a query object full of information about the films in the company's database. The value returned by the function is assigned to the local getFilms variable. From that point on, the getFilms query object can be used just as if there was an actual <cfquery name="getFilms"> tag on the page.

Now it just takes a simple call to makeFilmPopupLink() to create a pop-upenabled link for each film in the getFilms query. Through the magic of the UDF framework, that one line of code looks up the movie's title, obtains the correct URL to display details about the film, and generates the JavaScript code needed to pop up the detail page in a small window. And it's all eminently reusable.

Don't user-defined functions rock?

Категории