Passing A Variable Number Of "Nameless" Arguments Using CFInvoke And ArgumentCollection

Posted March 30, 2007 at 8:39 AM

Tags: ColdFusion

I have been trying to figure out how to send a variable, logic-based selection of arguments as unnamed values to a function. My original thought was to use ColdFusion's CFInvoke and CFInvokeArgument, but CFInvokeArgument requires a name attribute (which is what I was trying to avoid). I couldn't just call the function using function notation (ex. "Test()") as I needed to involve logic in my argument selection (which only CFInvoke would allow).

Sean Corfield had a good idea to use the index-like keys. But for some reason, it didn't click in my head until Christoph Schmitz suggested the same thing. While both suggested this solution, I think it only dawned on me "how" to accomplish this when Chris said it (right place, right time). Both are clearly rock stars though.

So anyway, here is my test to see that it works. These are two functions that I tested with. The first, DumpArgs() is the ColdFusion UDF that just dumps out its arguments. The second function, StructCreate() is just a utility function (seen all over the place) that builds a struct on the fly and returns it:

 Launch code in new window » Download code as text file »

  • <cffunction
  • name="DumpArgs"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Does nothing but CFDump out the arguments.">
  •  
  • <!--- Dump out arguments. --->
  • <cfdump
  • var="#ARGUMENTS#"
  • label="ARGUMENTS Scope"
  • />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="StructCreate"
  • access="public"
  • returntype="struct"
  • output="false"
  • hint="Returns a created struct based on the passed in key-value pairs.">
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  • <!--- Create the return struct. --->
  • <cfset LOCAL.Struct = StructNew() />
  •  
  • <!---
  • Populate the struct using the name-value pairs
  • of passed in arguments.
  • --->
  • <cfloop
  • item="LOCAL.Key"
  • collection="#ARGUMENTS#">
  •  
  • <cfset LOCAL.Struct[ LOCAL.Key ] = ARGUMENTS[ LOCAL.Key ] />
  • </cfloop>
  •  
  • <!--- Return struct. --->
  • <cfreturn LOCAL.Struct />
  • </cffunction>

Ok, now I need to create some values that I may OR may not need to pass in. It's friday, let's build a struct of hot girls that we can choose from:

 Launch code in new window » Download code as text file »

  • <!--- Create a struct of girls. --->
  • <cfset objGirls = StructNew() />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Samantha" ] = StructCreate(
  • Name = "Samantha",
  • Hair = "Brunette",
  • Hotness = 9.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Niki" ] = StructCreate(
  • Name = "Niki",
  • Hair = "Brunette",
  • Hotness = 8.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Lori" ] = StructCreate(
  • Name = "Lori",
  • Hair = "Blonde",
  • Hotness = 7.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Tamoko" ] = StructCreate(
  • Name = "Tamoko",
  • Hair = "Black",
  • Hotness = 8.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Ashley" ] = StructCreate(
  • Name = "Ashley",
  • Hair = "Brunette",
  • Hotness = 8.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Libby" ] = StructCreate(
  • Name = "Libby",
  • Hair = "Brunette",
  • Hotness = 9.0
  • ) />
  •  
  • <!--- Create girl. --->
  • <cfset objGirls[ "Christina" ] = StructCreate(
  • Name = "Christina",
  • Hair = "Blonde",
  • Hotness = 9.0
  • ) />

Now that we have a our function in place and our possible values, let's create a variable-length argument collection based on some business logic:

 Launch code in new window » Download code as text file »

  • <!---
  • Create an argument collection of girls. The
  • purpose of this is to build up a variable number
  • of "nameless" arguments.
  • --->
  • <cfset objArgs = StructNew() />
  •  
  • <!---
  • Loop over the girls to figure out which ones we
  • want to pass in. For now, let's get all the 9.0
  • who are also brunette.
  • --->
  • <cfloop
  • item="strGirl"
  • collection="#objGirls#">
  •  
  • <!--- Get a reference to the girl. --->
  • <cfset objGirl = objGirls[ strGirl ] />
  •  
  • <!--- Check to see if this girl makes the cut. --->
  • <cfif (
  • (objGirl.Hair EQ "Brunette") AND
  • (objGirl.Hotness EQ 9.0)
  • )>
  •  
  • <!---
  • We want to include this girl in our argument
  • collection. In order to do that we are going to
  • add her to the argument collection struct with an
  • index-based naming convention so that the function
  • will use it like an array. In order to do this
  • dynamically, we can use the struct-count to get
  • the current index.
  • --->
  • <cfset objArgs[ StructCount( objArgs ) + 1 ] = objGirl />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Now that we have built up the argument
  • collection, we can simply invoke the method and pass
  • in the arguments struct.
  • --->
  • <cfinvoke
  • method="DumpArgs"
  • argumentcollection="#objArgs#"
  • />

This gives us the following CFDump:


 
 
 

 
Variable Length Argument Collection CFDump  
 
 
 

That works perfectly! I think the thing that finally clicked in my head when Chris suggested the argumentCollection was how to build the struct without having to use an incrementing value (ie. keeping some sort of argument count variable). By using the StructCount() I was able to just keep appending values to the struct and not having to worry about what index I was actually working on. Sweet!

Note: Using argumentCollection can also be done with standard function invokation. It does not require the use of CFInvoke.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Mar 30, 2007 at 11:13 AM // reply »
2 Comments

Ben, take a look at my experimental CFC framework. This is exactly how i pass data between different methods. There are a few different viewlets demonstrating how it all works.

http://labs.webapper.net/projects/CFCFramework/index.cfm


Mar 30, 2007 at 12:51 PM // reply »
19 Comments

FWIW, #dumpargs(argumentcollection=objArgs)# would work just as well as <cfinvoke method="DumpArgs" argumentcollection="#objArgs#" />


Mar 30, 2007 at 2:48 PM // reply »
6,516 Comments

@Steve,

The PPT looks cool. I will take try to take a look at the other files this weekend.

@Matt,

Yeah, good point. I was just using CFInvoke cause that's how I started out. But you are absolutely right.


Apr 4, 2007 at 6:31 PM // reply »
6,516 Comments

@Steve,

I finally got around to going through your CFC framework. It looks pretty interesting. I see what you are saying about passing around all of your arguments like this; you are continually passing your ARGUMENTS scope onto other methods.

I don't know enough MVC / Fusebox to comment on the functionality, but it does look very clean. I am sure it will positively influence my future thought processes.


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »
Nov 20, 2009 at 5:23 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Todd, Ahh, gotcha, yeah that makes sense. ... read »
Nov 20, 2009 at 5:17 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
Ben, sorry if I didn't make this clear. You can make it work like that if you want, just put <cfset session.foo = 1> (and <cfset application.foo = 1>) in your OnRequestStart() and it reve ... read »