CFCs for the common developer Part 2
So last time we learned the basics of creating a CFC and the overall structure of a very basic CFC. Today we’re going to talk about the different ways in which we can use this CFC in our code.
So how do we access this function in our CFC? Can we just include it into a CFML page using the CFInclude tag or is there more to it? If you guessed there’s more to it then you are spot on! CFCs have a few ways in which they can be used, tag based, script based and yet another tag based implementation.
Tag Based Implementation #1
Now CFCs ,at their most basic level, are a lot like custom tags. In order to use the functions you create in a CFC you have to call them and then output the data they return. So for our greeting CFC we would call it like so:
<cfinvoke component="greeting" method="getGreeting" returnvariable="myGreeting"> <cfoutput>#myGreeting#</cfoutput>
This will display Welcome guest! Enjoy your visit and please come back soon. wherever we output the variable myGreeting. Here we are using the CFInvoke tag to “invoke” our CFC, which is just a fancy way of saying “to call”, “instantiate” or even “create”. The CFInvoke tag takes a good amount of attributes but we only care about 3 for now. Component is the name of the component we want to use. In the code above the greeting component lives in the same folder as the page which the CFInvoke tag is written. If I had the CFC in another folder I would use do notation to tell ColdFusion where to find my CFC. For example if my page lived in the root folder but my CFCs lived in a folder called components below my root folder I could use this code:
<cfinvoke component="components.greeting" method="getGreeting" returnvariable="myGreeting"> <cfoutput>#myGreeting#</cfoutput>
If my CFCs lived in a mapping called Global outside of my root folder but in a sub folder called CFC I would call it like so:
<cfinvoke component="Global.cfc.greeting" method="getGreeting" returnvariable="myGreeting"> <cfoutput>#myGreeting#</cfoutput>
You can even use variables when telling ColdFusion where to find your CFCs:
<cfinvoke component="#application.CFCPath#.greeting" method="getGreeting" returnvariable="myGreeting"> <cfoutput>#myGreeting#</cfoutput>
Now what if we wanted to pass in a visitors name how would we do that? Our CFC can take in an argument called “visitor” and to pass a value into this argument you would use the CFInvokeArgument tag like so:
<cfinvoke component="greeting" method="getGreeting" returnvariable="myGreeting"> <cfinvokeargument name="visitor" value="Eric"> </cfinvoke> <cfoutput>#myGreeting#</cfoutput>
You can see in the code above that we’ve added lines 2 and 3. Line 2 is the actual CFInvokeArgument tag and it takes two attributes, name which is the name of the variable in our CFC and value which is the value we want to pass into our CFC. Line 3 is the closing CFInvoke Tag which was absent in our previous examples. For those wondering you can pass in variables in the value attribute, just remember to pound (#) them.
Tag Based Implementation #2
So why would we need 2 ways to call a CFC with tags? Well implementation #1 is good and effective but the CFC only exists right then and there. When you call a CFC using the code in implementation #1 the CFC gets created by ColdFusion, you could also say instantiated which is the same thing, the function then gets called and that data gets output. THEN ColdFusion destroys the CFC and wipes it from existence in the servers memory, but not the file itself so don’t worry. Now this is fine if you don’t want to use the CFC or any of it’s functions later on but if decide that you do then ColdFusion has to go through this whole creation process all over again. In programming we call this creation / destruction process “expensive” because it uses memory and processor units to accomplish the task each and every time. It would be so much better if we could create the CFC and then store it in an application scope, or session scope and reuse it throughout the site and that is where implementation #2 comes in.
First we have to create the CFC and since we want the CFC to stick around this time we’re going to create it in our Application scope. For those unaware the Application scope is a persistent scope, meaning that any variables created in this scope will persist until they are over written, deleted or the server is restarted. It’s a great place to store things which you need throughout your entire application. Here’s the code to accomplish this little task:
<cfobject type="component" name="Application.siteGreeting" component="greeting"> <cfinvoke component="#application.sitegreeting#" method="getGreeting" returnvariable="myGreeting"> <cfinvokeargument name="visitor" value="Eric"> </cfinvoke>
For the most part this code look pretty similar to what we did in implementation #1 but with a twist. First off look at line 1 and you’ll see we’ve added a new tag called CFObject and it takes 3 attributes. The type attribute tells ColdFusion what we want to create and in this case it’s a component. Next up is name, this is the variable which will be created from this tag, which will be my CFC. Last is the component attribute and it works just like the component attribute does in our CFInvoke tag, meaning it tells ColdFusion where to find the component we want to create. Now once this tag runs we’ll have a persistent instance, or copy, of our CFC and we can reference it as Application.siteGreeting.
Next up we use our CFInvoke tag to actually use the CFC and call our getGreeting function. You’ll notice here that it’s exactly like implementation #1 with the exception of the component attribute. Here we are actually passing in the variable we created with our CFObject tag and pounding it out INSTEAD of passing it the path to our CFC. Now in this example I have the CFObject tag right before the CFInvoke tag but in reality the two tags could be multiple lines apart, or even in different files. As long as my application.siteGreeting gets created then my CFInvoke tag will run without any problems.
So why would we want to this? After all it is an extra line of code and is it really saving us that much? For this example no, probably not, but over time it could be very costly to keep creating and destroying our CFC using just the CFInvoke tag.Think if thousands of people hit this page at the same time. ColdFusion would be creating and destroying the same CFC each and every time the page was run. By creating it into a scoped variable it’s more persistent and it isn’t as expensive to use since it already exists. Think of it like buying a soda at a corner store. Each time you want to get a drink you have to go to the store, pick out your soda, pay for it at the register and then you get to drink it. This is how implementation #1 works but if you already had the soda, or even a case of soda, bought and they were sitting in your fridge you could cut out the “going to the store”, “picking it out”, and “paying for it at the register” steps because you already have it and can enjoy the soda whenever you want to.
CFScript based implementation
If you’re a script person, and I am sometimes for sure, you might like this version:
<cfscript> siteGreeting = CreateObject('component','greeting'); myGreeting = siteGreeting.getGreeting(visitor='Eric'); </cfscript>
<cfscript> application.siteGreeting = CreateObject('component','greeting'); myGreeting = application.siteGreeting.getGreeting(visitor='Eric'); </cfscript>
Version #1 and Version #2 are 99% identical with the exception that in version #2 we are creating the CFC in the application scope just like the tag based implementation #2. Here you see we’ve used the CFScript tag to setup the ColdFusion scripting environment. ColdFusion is primarily a tag based language and that’s what it’s know for but it also has a script side to it which allows you to do a lot, but not everything you can do in the tag side. Everything between the CFScript tags is ColdFusion script and it probably looks a lot like other scripting languages you’ve seen. In line 2 of the above examples we use the CreateObject function to create our CFC much in the same way we use the CFObject tag in implementation #2. When you create CFC’s via CFScript you have to always use the CreateObject function as there isn’t an all in one solution like the tag based CFInvoke. So version one we create the CFC and assign it to the variable siteGreeting and in version two it’s assigned to the variable application.siteGreeting. On line 3 we actually call our function using dot notation, remember dot notation from tag based implementation #1, using the format CFCNAME.functionName. Now since version two has the CFC in the application scope you get an extra dot in there, it’s more like scope.CFCNAME.functionName but it’s basically the same thing. You’ll notice that when I pass in our argument visitor I do it within the parenthesis as visitor=’Eric’. When doing CFC’s the CFScript way you can either pass your variables in this name=value pair or you can just pass in the values as a comma delimitated list, being sure to quote string values. BUT when you pass them in as a list you must pass the values in the exact order that your CFC has the cfargument tags setup. For example if my CFC looked like so:
<cfcomponent displayname="MyFirstCFC" hint="It's just a CFC folks, don't freak out"> <cffunction name="getGreeting" output="false" returntype="string" description="Returns a greeting string"> <cfargument name="visitorFirstName" required="no" type="string" displayname="Visitor First Name String" hint="The Visitors name"> <cfargument name="visitorLastName" required="no" type="string" displayname="Visitor Last Name String" hint="The Visitors name"> <cfif IsDefined('arguments.visitor') AND Len(Trim(arguments.visitor))> <cfreturn 'Welcome ' & arguments.visitorFirstName & ' ' & arguments.visitorLastName & '! I hope you enjoy your stay.'> <cfelse> <cfreturn 'Welcome guest! Enjoy your visit and please come back soon.'> </cfif> </cffunction> </cfcomponent>
Then I’d have to either pass in my variables like so:
myGreeting = application.siteGreeting.getGreeting(visitorFirstName=’Eric’,visitorLastName=’Jones’);
myGreeting = application.siteGreeting.getGreeting(‘Eric’,’Jones’);
Only in the first example where I do the name = value pair could I mix them up and put the “last name” first and the “first name” last without any issues. If I mixed them up in the second example then my name would get returned as “Jones Eric” instead of “Eric Jones”. Therefore it’s always a good idea to pass your arguments in the name=value pair unless you only have one argument to pass in.
Ok that concludes this post and I think I’m done with CFCs for the common developer for a short while but please feel free to post your questions here or on the forums. Who knows maybe you’ll inspire my next post!