I have finally got around to working a bit more on the fusebox scaffolder project. One of the things I have meaning to do was improve the generated code by using an abstract bean and letting generated beans inherit some base methods. I intend to do this for most of the generated cfcs, but just started with the bean as a first step.
I have not in the past used onMissingMethod but now enough of what I am doing is on CF8 that I decided it was worth incorporating in the generated code. I began by reading up about it to see
what
others
had
done.
There was certainly lots of ideas out there and I decided to take John Whish's dynamicAccessors.cfc and take it a bit further.
John's idea was to make use of the <cfproperty> tag to set up the properties in a cfc and then to make use of the onMissingMethod in a base cfc to create dynamic accessors. I really like this idea but I also like Peter Bell's idea for controlling the access to the getters and setters through a list of property names.
I was wondering about combining the two ideas and remembered somthing I discovered in the early days of CFCs. You can actaully create your own attributes on many of the CF tags just by adding them to the tag.
So I can write:
<cfproperty name="title" type="string" settable="true" gettable="true"/>
and ColdFusion will ignore my two new attributes in most respects. What it will do is add them to the metadata so I can read them. This allows me to extend John's getAccessors() method to update two new structures one for the setters and one for the getters.
<cffunction name="getAccessors"
hint="I build a structure of public properties and data types."
access="public">
<cfset var metadata = "" />
<cfset var properties = arrayNew(1) />
<cfset var index = "" />
<cfif StructKeyExists( variables.instance, "_properties" )
AND StructKeyExists( variables.instance, "_getable" )
AND StructKeyExists( variables.instance, "_setable" )
AND IsStruct( variables.instance._properties )
AND IsStruct( variables.instance._gettable )
AND IsStruct( variables.instance._settable )>
<cfdump var="#variables.instance._properties#"/>
<cfdump var="#variables.instance._gettable#"/>
<cfdump var="#variables.instance._settable#"/>
<cfabort/>
<cfreturn variables.instance._properties />
<cfelse>
<!--- The first time we get or set a property we need to build a structure of properties and types --->
<cfset variables.instance._properties = {} />
<cfset variables.instance._gettable = {} />
<cfset variables.instance._settable = {} />
<cfset metadata = getMetaData(this)>
<cfloop condition="structKeyExists(metadata,'properties') OR structKeyExists(metadata,'extends')">
<cfif structKeyExists(metadata,"properties")>
<cfset properties = metadata.properties />
<cfloop array="#properties#" index="index">
<cfif IsDefined("index.type")>
<cfset StructInsert( variables.instance._properties, index.name, index.type ) />
<cfelse>
<cfset StructInsert( variables.instance._properties, index.name, "any" ) />
</cfif>
<cfif IsDefined("index.getable")>
<cfset StructInsert( variables.instance._gettable, index.name, index.getable ) />
<cfelse>
<cfset StructInsert( variables.instance._gettable, index.name, "false" ) />
</cfif>
<cfif IsDefined("index.setable")>
<cfset StructInsert( variables.instance._settable, index.name, index.setable ) />
<cfelse>
<cfset StructInsert( variables.instance._settable, index.name, "false" ) />
</cfif>
</cfloop>
</cfif>
<cfif structKeyExists(metadata,"extends")>
<cfset metadata = metadata.extends>
<cfelse>
<cfset metadata = "">
</cfif>
</cfloop>
<cfreturn variables.instance._properties />
</cfif>
</cffunction>
I now have two new structures in my object which I can use to test if the generated code should allow you to set or get each property.
A small change to the onMissingMethod() function and I can now control who has access quite easily.
What I really want to know is: Am I mad to do this? After all I am arbitarily extending the language and I didn't ask anyones permission.
27Jan 16:25 GMT - Modified to fix a couple of typos.