By Peter Bell

Snippets: Extending the Generic Getter (and the hardGet() method)

In my last post I shared the design decisions and code for the generic getters I had previously enthused about. In this post I'll show how custom getters can easily be used to extend the business object with rules and I'll also share the currently fairly trivial code for the hardGet() method that encapsulates the pulling of data from within the iterating business object.

Lets start with a simple User object where you'd like to add a full name attribute based on first name and last name properties. You'd simply add a custom getFullName() method to your custom user object (which extends the base object) with the following code:

<cffunction name="getFullName" returntype="string" access="private" output="false" hint="I return the users full name.">
   <cfscript>
      var Local = StructNew();
      Local.ReturnValue = variables.hardGet('FirstName') & " " & variables.hardGet('LastName');
   </cfscript>
   <cfreturn Local.ReturnValue>
</cffunction>

Note that getFullName() is private. The interface to getters is the generic get(AttributeName) getter which handles the process of determining whether to use a default or custom getter, so as a best practice in this architecture, all custom getters (and setters) should be private.

You also need to make sure that the FullName is one of the "gettable" attribtues in the custom user init() pseudo constructor:

<cffunction name="init" returntype="UserObject" access="public" output="false" hint="I initialize the custom User object.">
   <cfscript>
      Super.Init();
      variables.gettableAttributes = "FirstName,LastName,FullName,Age";
   </cfscript>
   <cfreturn This>
</cffunction>

When a script calls User.get('FullName'), providing the attribute is "gettable" (a metadata setting in the user init() function), the generic getter will look for a getFullName() method. Finding it, it will call that method and return that value to the calling script. (If there wasn't such a script it would just use the generic hardGet(AttributeName) method described below).

As for the hardGet() method, it just gets a value from an array of structs based on the current row within the recordset and the name of the property being requested. Naturally hardGet() is a private method as it is only available to the generic getter and any custom getters.

<cffunction name="hardGet" returntype="any" access="private" output="false" hint="I am the 'hard' getter that other getters use to actually get an attribute value for the current record before working with it.">
   <cfargument name="AttributeName" type="string" required="yes" hint="The name of the attribute to get">
   <cfset var Local = StructNew()>
   <cftry>
   <cfscript>
      // Just pull the attribute
      Local.ReturnValue = variables.Data[variables.IteratorRecord][AttributeName];
   </cfscript>
      <cfcatch>
         <cfif variables.ReturnNullforNonExistantAttributes>
            <cfset Local.ReturnValue = "">
         <cfelse>
            <cfset Local.ReturnValue = "NON_EXISTANT_ATTRIBUTENAME(#arguments.AttributeName#)">
         </cfif>
      </cfcatch>
   </cftry>
   <cfreturn Local.ReturnValue>
</cffunction>

Comments
I'm wondering why you didn't go with throwing errors rather than returning strings that represent error conditions? I assume the next step in your framework is generic setters, custom setters and hardSet(), would have those return error strings as well?
# Posted By Ryan Miller | 7/31/06 12:30 AM
And I'm wondering how you handle sub-objects in your model. I'd love to discuss, email me if you like!
# Posted By Ryan Miller | 7/31/06 12:32 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.