Ask a Jedi: Problem using onMissingMethod inside a CFC

Matthew writes in with an interesting problem:

I'm using a onMissingMethod() to generate all my get/set methods I need, and I have an init() method in my cfc that calls a setDsn(arguments.dsn) and when I run it, it says setDsn() variable is undefined. Now if I change it to this.setDsn(arguments.dsn) then it works, and the onMissingMethod() is fired.

Good question. The reason why it didn’t work for you, and it worked when you used this.setDSN, is that onMissingMethod only works for outside calls (and remember this.X() acts like an outside call, which is why we don’t recommend using that format). It’s almost like ColdFusion says to itself “I’m not going to run onMissingMethod for internal calls because there is no way you are that stupid.”

To test this yourself, create a quick and dirty CFC with onMissingMethod support:

<cfcomponent output="false">

<cffunction name=”wrong”> <cfreturn doItFunk(1,2,3)> </cffunction>

<cffunction name=”onMissingMethod” output=”false”> <cfargument name=”missingMethodName” type=”string”> <cfargument name=”missingMethodArguments” type=”struct”> <cfreturn arguments> </cffunction> </cfcomponent> </code>

Now run this from a CFM:

<cfset test = createObject("component","test")>

<cfset res = test.doItFunky(1,2,3)> <cfdump var=”#res#”>

<cfset res = test.doItFunk(name=”paris”,age=35,style=”funky”)> <cfdump var=”#res#”>

<cfset res = test.wrong()> <cfdump var=”#res#”> </code>

The first two calls work just fine, but the third one will give you a method not found error.

So taking Matthew’s specific example - he has a generic bean and wants to init some values, but he can’t rely on onMissingMethod. Well the simplest thing to do is just directly set the value. If you are using a structure like variables.instance for your bean data, your init can just do:

<cfset variables.instance.dsn = "paris">

In all things remember the KISS rule! But if you want to get fancy, your onMissingMethod could chain to generic get/set methods. Consider:

<cffunction name="get" access="private" output="false" returnType="any"> <cfargument name="prop" type="string" required="true"> <cfreturn variables.instance[arguments.prop]> </cffunction>

<cffunction name=”set” access=”private” output=”false” returnType=”void”> <cfargument name=”prop” type=”string” required=”true”> <cfargument name=”value” type=”any” required=”true”> <cfset variables.instance[arguments.prop] = arguments.value> </cffunction>

<cffunction name=”onMissingMethod” output=”false”> <cfargument name=”missingMethodName” type=”string”> <cfargument name=”missingMethodArguments” type=”struct”>

&lt;cfset var property = ""&gt;
&lt;cfset var value = ""&gt;

&lt;cfif findNoCase("get",arguments.missingMethodName) is 1&gt;
	&lt;cfset property = replaceNoCase(arguments.missingMethodName,"get","")&gt;
	&lt;cfreturn get(property)&gt;
&lt;cfelseif findNoCase("set",arguments.missingMethodName) is 1&gt;
	&lt;cfset property = replaceNoCase(arguments.missingMethodName,"set","")&gt;
	&lt;!--- assume only arg is value ---&gt;
	&lt;cfset value = arguments.missingMethodArguments[listFirst(structKeyList(arguments.missingMethodArguments))]&gt;
	&lt;cfset set(property,value)&gt;
&lt;/cfif&gt;

</cffunction> </code>

All the onMissingMethod does is figure out if you are getting or setting, gets the values, and then runs the private methods. What’s nice then is that your init() function can use the same code:

<cffunction name="init" access="public" output="false" returnType="any"> <cfset set("name","Nameless")> <cfreturn this> </cffunction>

I’ll leave this blog entry with a quick reminder to remember that you must use the right argument names with onMissingMethod. See this blog post for more information: Warning about onMissingMethod

Raymond Camden's Picture

About Raymond Camden

Raymond is a developer advocate. He focuses on JavaScript, serverless and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Comments