<cfcomponent><cfcomponent> is the first and last tag in any component. To define a component, you simply put any number of methods (functions) into a file with the extension .cfc, and make sure that <cfcomponent> encloses the entire file. There are no required attributes for <cfcomponent>, but generally you'll want to use its optional attributes, displayname and hint, to produce self-documentation via introspection. TIP <cfcomponent> should be the first and last thing in any component file. Any CFML outside of the <cfcomponent> tags will cause the component to produce an error. Anything else, HTML or text, will be ignored. Another optional attribute of the <cfcomponent> tag is extends. This enables inheritance in CFCs; that is, it allows a component to "inherit" methods and properties from a "parent" component. We will cover this in depth later in this chapter. Finally, ColdFusion MX 7 adds support for document-literal Web services (Chapter 24, "Creating and Consuming Web Services") and creating gateways (Chapter 31, "Working with Gateways"). Both Web services and gateways extend the <cfcomponent> tag by adding a number of additional attributes, covered in depth in those chapters. <cffunction><cfcomponent> defines a component, but an empty component isn't much use without some functions inside it. Each function that a component can do is defined in a named block of code created with the <cffunction> tag. Listing 19.1 is some code from Macromedia ColdFusion MX Web Application Construction Kit (Macromedia Press) that defines a component used to access data from the Actors database. Listing 19.1. The Actors.cfc Component<!--- Actors.cfc - Orange Whip Studio Component As modified by Ken Fricklas (kenf@fricklas.com) Modified: 2/15/2005: getActorDetail shows all actors. ---> <cfcomponent displayname="Orange Whip Studio Actor Component" hint="This component manages OWS's Actor management system"> <cffunction name="getAllActors" displayname="Get All Actors" hint="Function to retrieve the name and ID of all actors" returntype="query" output="false"> <!--- Retrieve the actor's name and id, and return the query ---> <cfquery name="theActors" datasource="ows"> SELECT NameFirst, NameLast, ActorID FROM Actors ORDER BY NameLast </cfquery> <cfreturn theActors> </cffunction> <cffunction name="getActorDetail" displayname="Get Actor Detail" hint="Function to retrieve all details for a specified Actor ID, or all Actors." returntype="query" output="false"> <cfargument name="actorID" type="numeric" displayname="Actor ID" hint="The ID of the Actor to get. If missing, all actors are returned." required="no"> <!--- Retrieve all information for one or all actors ---> <cfquery name="theActor" datasource="ows"> SELECT * FROM Actors <cfif isdefined("arguments.actorID")> WHERE actorID = #arguments.actorID# </cfif> </cfquery> <cfreturn theActor> </cffunction> </cfcomponent> The first function, getAllActors, is the simplest since it takes no arguments. It must simply perform the database query and return the resulting recordset. Since we know in advance what kind of result it will produce, we can specify it with the returntype attribute. TIP The returntype attribute is useful in introspection but is not required for the function to work properly. If you want to expose the function as a Web service, however, returntype is required. This is because it will be mapped to a valid SOAP data type in the WSDL (see Chapter 24 for more information about Web services and data type mappings). If you elect to use returntype, Table 19.1 defines the options available. Some of the data types aren't necessarily obvious, so I've provided this list to discuss the details.
If anything else is specified as a return type, ColdFusion processes it as returning a component for which properties have been defined. This technique allows components to define complex types for Web services. Chapter 24 discusses this feature in depth. Typically, though, the standard data types will suffice. Our Actors master-detail application has two data-access actionscurrently each one a cfquery on each of the two CFML pages. Our Actors component, then, will have two methods, each defined with a <cffunction> tag. <cffunction> uses the same introspection attributes as <cfcomponent>: displayname and hint. Another attribute, output, can be set to "no" if your function doesn't write anything out. This works like a virtual <cfsilent> tag, and causes all the whitespace in a pure code function to be discarded by ColdFusion. If you set it to "yes", your function works as if the entire function is wrapped in a <cfoutput> tag, and anything in number signs (#) will be interpreted as ColdFusion variables. If you don't specify the output attribute, it works like any other ColdFusion codeyou need to either wrap output in <cfoutput> or use the WriteOutput() function. Finally, there are two additional arguments you can use when defining components in ColdFusion: roles, used to secure functionality by user; and access, used to both secure a component and hide implementation details. We'll come back to these later in this chapter. <cfargument>To define the arguments passed into a function, you use <cfargument>. Again, displayname and hint can provide more information for the folks using your component. The arguments also have data types, specified with the type attribute, from the same list as the returntype in the <cffunction> tag. Use the required attribute, set to "YES" or "NO", to indicate if an argument must be passed into a function. This causes ColdFusion to throw an error if the argument isn't passed in, and makes the function more self-documenting. Finally, if your attribute isn't required, default allows you to specify a default value for any argument. The order of your cfargument tag is important. If your user is calling your method using function syntax (see the later section on calling with <cfobject>) they may want to specify the arguments in the order you've put them in the function. For this reason, its generally a good idea to put your required arguments before the optional ones. NOTE All <cfargument> tags are placed in the function before any other code. If anything comes before them, ColdFusion produces an errorbut not a very intuitive error. It will say "Context validation error for tag cffunction" and will mention that a <cffunction> tag needs a matching end tag. So if you do have both <cffunction> tags and still get this error, check for stray <cfargument>s. TIP If you have object-oriented language experience, you might be expecting ColdFusion to allow you to redefine your functions with different <cfattribute> types, or different numbers of required attributes, in order to have separate function handlers handle different types and numbers of attributes (called "overloading.") SorryColdFusion's object-oriented behavior doesn't go quite that far; there's no overloading in ColdFusion. Trying to redefine a function just causes an error. However, you can simulate this kind of behavior using inheritance, described in "Inheritance" later in the chapter. Variable Numbers of ArgumentsFunctions in ColdFusion do not require a fixed number of attributes. If you pass more attributes than the function is expecting, the function will work properly, allowing you to use variable numbers of arguments for functions that need them. Since arguments to ColdFusion functions are available in an array called "arguments", you can figure out how many arguments you have by looking at that array. Here's a short function that adds however many numbers are passed in: <cffunction name="addemup" returntype="numeric"> <cfset ret = 0> <cfloop from="1" to="#arrayLen(arguments)#" index="i"> <cfset ret = ret + arguments[i]> </cfloop> <cfreturn ret> </cffunction> We can call this function with: <cfoutput>#addEmUp(1,2,3,4,5)#</cfoutput> As you can see, here's a function that takes any number of argumentsincluding zeroand returns a value. <cfreturn><cfreturn> returns the value from the function. The type it returns must be the type you specified in the <cffunction> tag, or ColdFusion will return an error. The only thing to remember is that value is an expression and it is only one expression. Returning multiple values from a CFC function is allowedyou'll just have to use a structure to do it. Since our getAllActors function needs to return just the one query recordset, we can simply code <cfreturn queryName>. |