Aliaspooryorik
ColdFusion ORM Book

argumentCollection - learn it and love it!

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!


6 comments

  1. Great post!

    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
  2. Hey Steve! I've never actually used cfinvoke like that, but it's a good alternative way to do it. Thanks for the comment :)

    Comment by John Whish – February 17, 2010
  3. ArgumentCollection is definitely cool; it took me a while to accept the fact that I had to use the "name argument" - argumentCollection - to get it to work; but once I accepted that, it was sweet!

    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
  4. Absolutely right, Ben. Though I don't see an advantage to cfinvoke with argumentcollection unless the method name is also dynamic.

    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
  5. Pretty cool!

    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
  6. Sorry to resurrect an old post but this just helped answer a question I had so I thought I would pass along an example of why you might use both argument approaches together.

    I'm calling a CFC and passing in most of what I need from the FORM scope. The CFC uses the form field names as arguments. However I also need to pass in a UserID value from the SESSION scope. So I use argumentCollection="#form#" in the cfinvoke tag and then add a cfinvokeargument tag to also pass the session variable.

    <cfinvoke component="app.cfc.ClientEngagement" method="insertCENote" argumentCollection="#Form#">

    <cfinvokeargument name="CE_UserID" value="#session.UserID#">

    </cfinvoke>

    Comment by Mickey – August 26, 2011

Leave a comment

If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)

Please note: If you haven't commented before, then your comments will be moderated before they are displayed.

Please subscribe me to any further comments
 

Search

Wish List

Found something helpful & want to say ’thanks‘? Then visit my Amazon Wish List :)

Categories

Recent Posts