The "doing-it-in-a-CFC" debate has been continuing over on Ray's blog, with several people coming down on the side of custom tags and tagset lbraries.
Nearly anything you can do in a nested tag configuration can be done in a CFC quicker and easier, plus in a cfc you can break functionality down into internal subroutines, inherit code from parent components, and you can get and assign values back w/o doing nasty returnvalue/caller syntax where you inject variables into the parent's scope.
Let's look at an autogenerating form example. First, a tagset-based version that's getting its data from an object:
<cf_form>
<cf_formfield tag="hidden" name="id"
value="#object.getID()#">
<cf_formfield tag="input" label="First Name" name="fn"
value="#object.getFirstName()#" size=25 required=1>
<cf_formfield tag="input" label="Last Name" name="ln"
value="#object.getLastname()#" size=25 required=1>
<cf_formfield tag="input" label="E-Mail Address" name="em"
value="#object.getEmail()#" size=25 required=1>
<cf_formfield tag="select" label="Gender" name="sx"
value="#object.getSex()#" size=1>
<cf_formfield tag="option" label="Male" value="M">
<cf_formfield tag="option" label="Female" value="F">
...
</cf_form>
Now, the component-based version:
<cfscript>
f=createObject('component','form').init();
f.hidden(name='id');
f.input(label='First Name', name='getFirstName()', size=25, required=1);
f.input(label='Last Name', name='getLastName()', size=25, required=1);
f.input(label='E-Mail Address', name='getEmail()', size=25, required=1);
f.select(label='Gender', name='getSex()', size=1);
f.option(label='Male', value='M');
f.option(label='Female', value='F');
...
</cfscript>
<cfoutput>#f.display(object)#</cfoutput>
It looks like fundamentally we've added two lines of code to do the createObject and cfoutput. On the flip side, each line is quite a bit shorter, mostly due to the fact that my form component knows how to call my object's getter functions and loads the data automatically.
Syntax-wise, the component version may seem a little odd. Then again, if you're using a tagset probably already cross-training someone who knows input and select into translating select into cf_formfield type="select". Is f.select(...) that much harder? Or easier? Or just six of one, half-dozen of the other?
So, both pretty much the same, right? But with the tagset we've only generated the form. How about processing it? Here's the minimal set of code needed to handle our tagset generated form, with pretty bad error handling:
<cfif structKeyExists(form,"id")> <cfparam name="form.fn" default=""> <cfparam name="form.ln" default=""> <cfparam name="form.em" default=""> <cfparam name="form.sx" default=""> <cfif trim(form.fn) is ''><cfthrow message="First Name Missing"></cfif> <cfif trim(form.ln) is ''><cfthrow message="Last Name Missing"></cfif> <cfif trim(form.em) is ''><cfthrow message="E-Mail Address Missing"></cfif> <cfset object.setFirstName(form.fn)> <cfset object.setLastName(form.ln)> <cfset object.setEmail(form.em) <cfset object.setSex(form.sx)> <cfset object.save()> </cfif>
Walking the code, it looks like we have to make sure our fields exist, error check our three required fields, assign our form values to the object, and then save it. How about with the component-based version?
Well, since we've already done our field definitions, we can shorten this up a little bit:
<cfif f.process(object)>
<cfset object.save()>
</cfif>
Now THAT'S significant.
Since our component "knows" what fields we generated, it also knows which ones to look for when we're processing the results, can do the cfparams internally, can do the error checking internally, and can call the object's setter functions to reassign the form values.
In real life we'd tend to put our form definitions inside a dedicated form component that extends our base form. Which shrinks our first component-based example down to:
<cfset f=createObject('component','member.form.registration').init()>
<cfoutput>#f.display(object)#</cfoutput>
All-in-all, cfc's are so superior in terms of power and functionality and extensibility and packaging that I stopped doing nested tag configurations years ago, and never looked back.
Admittedly, you need the proper components to do this kind of work and to have access to this kind of power... but that's why we're here, isn't it?
good..thanks
http://shariffdotnet.blogspot.com
Posted by: shariff | November 16, 2008 at 11:56 PM