Matthew writes in with an interesting problem:
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."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.
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>
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#">
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">
<cfset var property = "">
<cfset var value = "">
<cfif findNoCase("get",arguments.missingMethodName) is 1>
<cfset property = replaceNoCase(arguments.missingMethodName,"get","")>
<cfreturn get(property)>
<cfelseif findNoCase("set",arguments.missingMethodName) is 1>
<cfset property = replaceNoCase(arguments.missingMethodName,"set","")>
<!--- assume only arg is value --->
<cfset value = arguments.missingMethodArguments[listFirst(structKeyList(arguments.missingMethodArguments))]>
<cfset set(property,value)>
</cfif>
</cffunction>
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
Archived Comments
This might be breaking the KISS approach, but you could have the get and set methods in your CFC set to private and then use the onMissingMethod to handle a call to setXyz(a=1) from an external script. onMissingMethod would then call the private get or set methods.
That way you can carry using setXyz() and getXyz() externally as you were before.
Um.... isn't that exactly what my code does? I must be missing something.
Sorry, being dense - that's exactly what you've done! End of the day... :-/
Thanks Ray again for your clarifications and help.
Nice. I've never encountered this problem because I am in the camp that is against generic setters and getters for public accessors. Not that I feel strongly about it; it's just not what I prefer. Although I always have generic setters and getters that are only private (just like in your example) and then used by my publicly accessible explicit getters and setters.
Have you ever tried using onMissingMethod with a webservice? I'm building a webservice now, and it seems not to work.
<cffunction name="onMissingMethod" access="remote" output="false" returntype="any">
<cfargument name="missingMethodName" type="string">
<cfargument name="missingMethodArguments" type="struct">
<cfset handleError("invalidmethod") />
</cffunction>
That's not possible. Web Services have a WSDL - which is basically a list of the services they provide. You can't support a 'do anything' dynamically type interaction.
You could though write a method that lets you specify another method to run. A method "broker" so to speak. You would want to be extra careful though.
Ah that makes sense. Thanks for the info.
I have posted a simple example on onMissingmethod here.
http://cf-examples.net/inde...