Sam Farmer

Growing up I never imagined I would play bass guitar for the Dave Matthews Band. And indeed it never happened.

But I have become passionate about making software.

Dynamically injecting data into an Object

December 18, 2009
I like to write as little code as possible (that’s the whole point of coding, right?) and recently, since I started working with ORM, have found the need to inject data into an object. Often with an ORM object -- though this isn’t limited just to ORM -- you create a new object then have lines of setXXX functions like so:
 
s = entityNew( 'Sample' );
s.setAge( form.age );
s.setFirstname( form.firstname );
 
Well I got pretty bored of writing all those setXXX lines. So I wrote a function to do it. (This is not the only way or necessarily the best way but I thought I would put it out there).
 
<cffunction name="injectInto">
<cfargument name="obj" required="true" hint="I am an object for injecting">
<cfargument name="st" required="true" hint="I am a structure of data.">
<cfloop collection="#arguments.st#" item="local.key">
            <cfif structKeyExists( obj, "set#local.key#" )>
                        <cfinvoke component="#arguments.obj#" method="set#local.key#" >
                        <cfinvokeargument name="#local.key#" value="#arguments.st[ local.key ]#">
                        </cfinvoke>
            </cfif>
</cfloop>
</cffunction>
 
First off this is all in tags as there is no invoke function in cfscript. Originally the if structKeyExists line was a try and catch. That worked but felt a little like overkill so I experimented around and found that structKeyExists works as I blogged about. I also tried using getComponentData which returns all functions but again this felt heavy to me.
 
So, what does the function do? It takes in an object that you want injected and a structure of data to inject into it, loops over that data, checks to see if the object publicly wants it and if so uses cfinvoke to give it to the object. The above code now becomes:
 
s = entityNew( 'Sample' );
s injectInto( s, form );
 
But what if you have data in multiple structures; form, url, request for instance? 
 
<cffunction name="injectInto">
<cfargument name="obj" required="true" hint="I am an object for injecting">
<cfloop from="1" to="#structCount( arguments )#" index="local.collection" >
            <cfif isStruct( arguments[ local.collection ] )>
                        <cfloop collection="#arguments[ local.collection ]#" item="local.key">
                                    <cfif structKeyExists( obj, "set#local.key#" )>
                                                <cfinvoke component="#arguments.obj#" method="set#local.key#" >
                                                <cfinvokeargument name="#local.key#" value="#arguments[ local.collection ][ local.key ]#">
                                                </cfinvoke>
                                    </cfif>
                        </cfloop>
            </cfif>
</cfloop>
</cffunction>
 
The above function will take in any number of structures and inject their data into the object. You may notice that the function only has one argument even though I just said it can have an endless number of arguments. That’s because I am going to programatically deal with them.
 
Regardless of how many arguments a ColdFusion function has defined it will always take in everything you give it. (Its generous like that! ;) ) If the arguments are not named then they take a number in the arguments structure. Let’s call the above function and then dump its arguments passed into injectInto.
 
//setting up some “fake” structures for form, url and request
f = { age="23" };
u = { firstname="Sam", age="21" };
r= { userID=2134132 };
sObj = new Sample();
injectInto( sObj, f, u, r );
 
 
As you can see the only named argument is the first one passed in – obj, the others get numbers for names. This is useful as it preserves the order they are passed and means we can loop over them and inject their data into the object which going back to the injectInto function is exactly what happens.

No Comments

Some comments have been lost over the years due to moving hosts.

More


More blog entries that I have written.

Code coloring by PRISM.