argumentCollection - learn it and love it!
February 16, 2010
I've been working on a project that someone else wrote recently and, whilst the code works, I'm finding things that I think could be improved by knowing a few of the cool features Coldfusion has. I'm posting this in case other developers aren't aware of what you can do.
Last time I blogged about per-application mappings, this time it is the turn of the argumentCollection parameter!
Take the following simple code example:
<cfcomponent output="false"
hint="I am a generic DAO (singleton) that gets data from the database">
<cffunction name="init"
output="false"
returntype="GenericDAO">
<cfargument name="datasource"
required="true"
type="string">
<cfset instance.datasource = arguments.datasource>
<cfreturn this>
</cffunction>
<cffunction name="findByFilter"
output="false"
returntype="query">
<cfargument name="deptid"
required="false"
type="numeric">
<cfargument name="prefix"
required="false"
type="string">
<cfset var result = "">
<cfquery name="result" datasource="#instance.datasource#">
SELECT personid, deptid, firstname, surname, extension
FROM Employees
WHERE 1 = 1
<cfif StructKeyExists( arguments, "deptid" )>
and deptid = <cfqueryparam value="#Val( arguments.id )#" cfsqltype="cf_sql_integer">
</cfif>
<cfif StructKeyExists( arguments, "prefix" )>
and firstname LIKE <cfqueryparam value="#( arguments.prefix )#%" cfsqltype="cf_sql_varchar">
</cfif>
</cffunction>
<cfreturn result>
</cffunction>
</cfcomponent>
The code that was calling this CFC to get a list of employees looked something like this:
<cfif StructKeyExists( url, "department" )>
<cfif StructKeyExists( url, "startswith" )>
<cfset q = application.genericDAO.findByFilter( deptid=url.department, prefix=url.startswith )>
<cfelse>
<cfset q = application.genericDAO.findByFilter( deptid=url.department)>
</cfif>
<cfelseif StructKeyExists( url, "startswith" )>
<cfset q = application.genericDAO.findByFilter( prefix=url.startswith )>
<cfelse>
<cfset q = application.genericDAO.findByFilter()>
</cfif>
Now that is a lot of code to do something really simple - and if you add more arguments, it will get even messier. ColdFusion allows you to pass an struct of values to your methods, using a parameter calling argumentCollection. This allows us to rewrite the previous code to look like this:
<cfset args = {}>
<cfif StructKeyExists( url, "department" )>
<cfset args.deptid = url.department>
</cfif>
<cfif StructKeyExists( url, "startswith" )>
<cfset args.prefix = url.startswith>
</cfif>
<cfset q = application.genericDAO.findByFilter( argumentCollection=args )>
Now that is much easier to read and maintain!
- Posted in:
- Coldbox
5 comments
Leave a comment
If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)





I would just add that cfinvoke is another option to accomplish the same thing:
<cfinvoke returnvariable="q" component="#application.genericDAO#" method="findByFilter">
<cfif StructKeyExists( url, "department" )>
<cfinvokeargument name="deptid" value="#url.department#">
</cfif>
<cfif StructKeyExists( url, "startswith" )>
<cfinvokeargument name="prefix" value="#url.startswith#">
</cfif>
</cfinvoke>
I think the choice comes down to personal preference, but they are both good options to have.
Comment by Steve Bryant – February 16, 2010
Comment by John Whish – February 17, 2010
To add to @Steve's comment, I believe argumentCollection will also work as part of the CFInvoke tag itself:
<cfinvoke argumentcollection="..." />
Comment by Ben Nadel – February 17, 2010
I wonder if it is possible to combine argumentCollection with named arguments in cfinvoke. Something to test out...
Comment by Steve Bryant – February 18, 2010
You can use cfinvoke with both argumentCollection and cfinvokeargument. You can even do so with each setting the same argument (cfinvokeargument wins).
I haven't thought of a use for this yet, but I am glad to know it.
Comment by Steve Bryant – February 18, 2010