CFCs (ColdFusion Components) Tutorial

(By Eric Korson)

Topics Include

Understanding Objects in CFCs (ColdFusion Components)

I would like to briefly discuss a few terms from the object-oriented language that you might normally use. Understanding these terms will help when working with components.

Object
  • An object is an abstraction that is essentially a function containing variables and methods.
    In ColdFusion, we generally refer to objects as component (CFC) instances.
Class
  • A class is a template that is used to create a new object (the new object is called an instance) and defines the variables; and, methods for all objects of a certain type.
    In ColdFusion, classes are implemented as CFCs. Individual objects are defined as instances of a particular CFC (a class).
Component
  • In other object-orientated environments, a component has a different meaning.
    In ColdFusion, we refer to a CFC as a component.
Method
  • A method is essentially functions that are part of an object. Methods allow the object to do something.
    In ColdFusion, CFC methods are written exactly like tag based UDFs (User Defined Functions) using the <cffunction> tag. A component is essentially a collection of related UDFs grouped within a <cfcomponent> container. For example a method can query a record from a database.
Property
  • Properties are attributes of an object (instance variables).
    In ColdFusion components, properties are variables you set in this (public) scope or the variables un-named (private) scope. Don´t confuse this type of property with the ColdFusion <cfproperty> tag. The <cfproperty> tag is used purely for declaring component metadata (data for other data). For example, my user object could have a property for the user’s first name.
Instance
  • An instance is an object of a particular class; and, the process of creating them is called instantiation.
    In ColdFusion, you get a component instance when you call a CFC using the <cfobject> tag or the createObject() function.
Constructor
  • In object-oriented programming, constructors are pseudo-methods that are used to create an instance of an object. In Java, constructors are methods with the same name as the class.
    In ColdFusion, a constructor is any code contained in a CFC that is not part of a method or property. Constructor code executes in ColdFusion each time an instance of the CFC is created. You can not pass arguments to the CFCs constructor; so, the use of the constructors is fairly limited in ColdFusion. Most programmers prefer to create an init() method to act as the default constructor for their CFCs.
Inheritance
  • Inheritance refers to an objects ability to automatically inherit the variables and methods of its parent (super or base) class.
    In ColdFusion, this translates to a CFCs ability to inherit all methods, variables set in the constructor area, <cfproperty> metadata tag; and, anything else that CFC inherits as well.
Introspection
  • Introspection is the ability for a component (or class) to examine itself.
    In ColdFusion, introspection is supported in several methods. Dreamweaver; and, Flash both have component browsers that can be used to introspect CFCs. Additionally, CFML contains a function called getMetaData() that can be used to return a structure containing all the properties, methods, arguments, return types; and, other metadata for a given CFC. ColdFusion also comes with a CFC Explorer that you can use to introspect any CFC on your server. Simply open up your browser; and, enter the URL to the CFC you would like to introspect. You should be presented with the CFC login screen.

Back To Top

Seven Ways to Instantiate and Invoke a CFC (ColdFusion Component)

Typically, you create an instance of a component; and then, call a method on it, passing data in the form of arguments. There are seven different ways in which you can call a component.

1). createObject() - The createObject() function instantiates the CFC (ColdFusion Component) as an object via <cfset>, <cfparam> or <cfscript>. Methods must be explicitly called and properties must be explicitly set (or arguments passed in).

Option 1 (preferred) - If your CFCs are mapped as they should be, this will work throughout your ColdFusion server.

<––– Instantiate the the User CFC (ColdFusion Component) –––>
<cfset myUserCfcObject = createObject("component","cfcs.user")>


I created an object (or instance) of the user.cfc. Now all the methods within the user.cfc are available to me by invoking my new object I named myUserCfcObject. For example, lets assume that I had a method within the user.cfc named getUser that required one argument to be passed in, the user id.


<––– Invoke the getUser Method –––>
<cfset myUsersQuery = myUserCfcObject.getUser(userId)>
<cfdump var=#myUsersQuery#" label=My Users Query Information">


I invoked the getUser method within the user.cfc and I now have query of the users information held within my local variable I named myUsersQuery.


Option 2


<cfscript>
      // Instantiate the the User CFC (ColdFusion Component).
      myUserCfcObject = createObject("component","cfcs.user");
      // Invoke the getUser Method.
      myUsersQuery = myUserCfcObject.getUser(userId);
</cfscript>


Also see the User CFC (ColdFusion Component) below under Creating a CFC (ColdFusion Component).
2). <cfinvoke tag - Instantiates a CFC and/or invokes a method on an instantiated CFC.

<––– Instantiate the the User CFC (ColdFusion Component) & Invoke the getUser Method –––>
<cfinvoke component = cfcs.user" method=getUser" returnVarible=myUsersQuery">
<cfinvokeargument name=userId" value=#userId#">
<cfdump var=#myUsersQuery#" label=My Users Query Information">
3). <cfobject tag - Properties must be explicitly set and methods explicitly called.

<cfobject component=cfcs.user" name=myUserCfcObject">
<cfinvoke component=#myUserCfcObject#" method=getUser" returnVariable=myUsersQuery">
<cfinvokeargument name=userId" value=#userId#">
<cfdump var=#myUsersQuery#" abel=My Users Query Information">
4). URL - Invokes a component method directly via HTTP GET. The CFC file name is specified in the URL along with the method name as a URL parameter.

http//example.com/cfcs/user.cfc?method=getUser&userId=301
5). Form Post - The Action attribute of the HTML <form> or <cfform> tag posts directly to a CFC. The method to call must be specified by the form field.

<form action=user.cfc" method=post">
      <input type=hidden" name=method" value=getUser">
      <input type=text" name=userId"> Please enter the User Id
      <input type=submit">
</form>
6). Web Service - CFCs can be consumed as web services.

<cfscript>
      myUserCfcObject = createObject("webservice","http://example.com/cfcs/user.cfc?wsdl");
      myUsersQuery = myUserCfcObject.getUser(userId);
</cfscript>


Or assuming that you registered the web service under an alias name as "userWebService", you don´t have to remember the long WSDL path.

<cfinvoke webservice ="userWebService" method="getUser" returnVarible="myUsersQuery">
      <cfinvokeargument name="userId" value="#userId#" />
</cfinvoke>


Keep in mind, you don´t have to manually create a WSDL file for each of your web services, although you could. The ColdFusion server automatically does it for you. For example, the address of the "department" Web Service is http://example.com/cfcs/department.cfc?wsdl.

7). Flash Remoting - Flash animations can call CFCs (ColdFusion Components) via Flash Remoting. This example could take a bit more of explaining; so, I am going to skip this example and move forward.

Back To Top

Creating a CFC (ColdFusion Component) & <cfscript> example

This updateUser Method (user.cfc example below) might be a little more complex for the beginner programmer but lets discuss. I created an update method within my user component. In reality, I should have one insert (or create) method, one update method; and, one delete (or hide) method for my user.cfc below.

<cfcomponent displayname="User">
	
  <cffunction name="getUser" access="public" returntype="query" output="0">
    <cfargument name="userId" type="numeric" required="yes" default="0">
	<cfset var thisUserId = trim(arguments.userId)>
	<cfif isValid("integer",thisUserId)>
		<cfquery name="qryGetUser" datasource="#application.DSN#">
			SELECT * FROM tblUsers
			WHERE user_id = <cfqueryparam cfsqltype="cf_sql_integer" value="#thisUserId#">
		</cfquery>
	<cfelse>
		<--- Return an empty query if the argument is not an integer --">
		<cfquery name="qryGetUser" datasource="#application.DSN#">
			SELECT * FROM tblUsers WHERE user_id = 0
		</cfquery>	
	</cfif>
     <cfreturn qryGetUser>
  </cffunction>
	
  <cffunction name="updateUser" access="public" returntype="boolean" output="0">
    <cfargument name="userStructure" type="struct" required="yes">
	<cfscript>  
	  valueSet = "";
	  for (key in myStruct) {
	    if(myStruct[key] NEQ ""){
		  valueSet = listAppend(valueSet,key & "='" & utilityObj.sqlSafe(myStruct[key]) & "'"); 
		}else{
		  valueSet = listAppend(valueSet,key & "='" & myStruct[key] & "'");
	    }
	  }
	</cfscript>
	<cftry>
	  <cfstoredproc datasource="#application.DSN#" procedure="dbo.sp_update_user">
	  <cfprocparam value="#arguments.userId#" cfsqltype="cf_sql_varchar">
	  <cfprocparam value="#valueSet#" cfsqltype="cf_sql_varchar">
	  <cfprocresult name="qA">
	  </cfstoredproc>
	  <cfcatch type="database">
	    <cfoutput>#cfcatch.detail#</cfoutput><cfabort>
	  </cfcatch>
	</cftry>
     <cfreturn>
  </cffunction>
  
</cfcomponent>

Back To Top

Working with ColdFusion Structures & Security for SQL Injection

Notice above (user.cfc) in my updateUser method, I am passing a ColdFusion structure. Using this design, I can do all my updates to user table through this one component method. In my example, when I pass a structure to the SQL database, it doesn´t matter in what order the fields come; or, the number of fields I pass as long as I follow the SQL rules. For example, the field names in my structure must match the field names in the database or I would receive a column name mismatch error.

Second, notice within my <cfscript> code, as I build the valueSet within my loop valueSet = listAppend(valueSet,key...) to pass to my SQL stored procedure, I also call my sqlSafe method (utilityObj.sqlSafe(userStructure[key])) to strip out any unwanted characters. The possible SQL injection is handled at the component level; and, acts as another security feature towards SQL injection (among my other security features). Once executing the <cfscript> tag, the variable of valueSet would look like: fname = ´Eric´, lname = ´Korson´ assuming the submitted form contained fname and lname; and, I entered Eric Korson.

Last, If I wanted to make this method a web service, I would only need to specify access=remote" above.

Back To Top

Improving Performance

Using CFCs (ColdFusion Components) increases performance because they only have to be compiled the first time they are called. After compiled once, the object remains in cache for all subsequent calls to that component; and, you can re-use the object without having to call it again within your webpage.

Back To Top

Would you consider ColdFusion to be an object oriented language?

CFML is not an object-oriented language, why? Objects are simply reusable application bits. They are black boxes, or magical things that do stuff, whatever you define that stuff to be. Objects often contain not just code (like CFCS) but also data, allowing data and any code that accesses it, to be cleanly encapsulated. Objects usually have multiple entry points (methods). They provide a mechanism to automatically run initialization code regardless of the entry point (a constructor). Objects can be adapted and modified, leveraging existing code without actually modifying (and potentially breaking) any of it in the process (inheritance).

For example: In ColdFusion, to perform operations on a user, you would first create an instance of the user object, and then you would be able to call a method upon it, by passing in the required arguments, for example...

<cfset myUserCfcObject = createObject("component","cfcs.user")>
<cfset myUsersQuery = myUserCfcObject.getUser(userId)>


or to do an update to the user, something like...

<cfset myUserCfcObject = createObject("component","cfcs.user")>
<cfset myUserCfcObject.updateUser(userId, newPhoneNumber)>


In an object-oriented world, you would have written your application very differently. You would have created a user object (a black box) that contained everything you needed for the users method. The idea is that any and all user processing would happen inside the user object. You would never access user tables directly. Actually, you wouldn't even know (or care) that the data is being stored in a table. You would just invoke methods as needed, letting the code inside the object do its thing. This is the kind of functionality is made possible using CFCs.

Back To Top