Aug 13 2007

Model Glue Tips Part 5: Maximize your re-usability with message arguments

Posted by Mark Drew at 2:00 PM
5 comments
- Categories: model-glue

As shown in the previous post, there is the ability to pass messages back to a message-listener with added information in the form of arguments. This can come in quite handy and allows you to make your controllers a bit more dynamic and re-usable so that they are useful under different situations. I shall give an example, which you should have spotted if you read the GenericList documentation, but I shall go into more depth here.Lets say we have a simple query in our service, that gets users, but you can also pass in a name filter, and an order by column. To call this method in the service, you could: a) Create multiple message-listeners in your controller or b) Create a single clever message-listener that expects different arguments Solution b sounds a little bit smarter doesn't it? So, lets prototype this, here is our service function definition, you can imagine that there is some nifty SQL or whatever in there: <cffunction name = "getPeople" returnType = "query" access = "public">
      <cfargument name="filterby" type="string" required="false" default="">
      <cfargument name="filterstring" type="string" required="false" default="">
      <cfargument name="orderby" type="string" required="false" default="">   
         
         ... some sql to do get the People ....
         
   </cffunction>
Initially you would call it as follows: ModelGlue.xml: <message name="getPeople"></message> This would simply get the people, and the controller would return it in the qPeople value (see the code below) in the Viewstate. Controler Code: <cfinvoke component="#variables.PeopleService#" method="getPeople" returnVariable="r_qPeople">   
   </cfinvoke>
   <cfset event.setValue("qPeople", r_qPeople)>
Ok, that is pretty basic, but lets say I don't like it being in the qPeople variable, I can change the behavior by adding a little bit of code in the controller, so if you now pass an argument to the message-listener like this: ModelGlue.xml: <message name="getPeople">
      <argument name="retVariable" value="qMyPeople"/>
   </message>
And in the controller code, we remove the hard coded "qPeople" and put in the value of the argument we passed in (with a default of course, don't want our old code to break!) by putting event.getArgument("retVariable", "qPeople") : <cfinvoke component="#variables.PeopleService#" method="getPeople" returnVariable="r_qPeople">   
   </cfinvoke>
   <cfset event.setValue(event.getArgument("retVariable", "qPeople"), r_qPeople)>
Mow the results would be returned into the qMyPeople variable in the View State. We can get even cleverer, we could add a filter to our ModelGlue.xml: <message name="getPeople">
      <argument name="retVariable" value="qMyPeople"/>
      <argument name="filterby" value="name" />
      <argument name="filterstring" value="Mark Drew"/>
   </message>
Controller Code: <cfinvoke component="#variables.PeopleService#" method="getPeople" returnVariable="r_qPeople">
      <cfif event.argumentExists("filterby") AND event.argumentExists("filterstring")>
         <cfinvokeargument name="filterby" value="#event.getArgument("filterby")#">
         <cfinvokeargument name="filterstring" value="#event.getArgument("filterstring")#">
      </cfif>
         
   </cfinvoke>
   <cfset event.setValue(event.getArgument("retVariable", "qPeople"), r_qPeople)>
Now we are filtering by the string "Mark Drew"! This is useful only if you want to hard code "Mark Drew" in your ModelGlue.xml file, but you will probably want to pass in a variable through a form or url, so we could change the controller code to say something like: <cfinvoke component="#variables.PeopleService#" method="getPeople" returnVariable="r_qPeople">
      <cfif event.argumentExists("filterby")
            AND event.argumentExists("filterstring")
            AND event.valueexists(event.getArgument("filterstring"))>

         <cfinvokeargument name="filterby" value="#event.getArgument("filterby")#">
         <cfinvokeargument name="filterstring" value="#event.getValue(event.getArgument("filterstring"))#">
      </cfif>
         
   </cfinvoke>
   <cfset event.setValue(event.getArgument("retVariable", "qPeople"), r_qPeople)>
And our Model Glue to: <message name="getPeople">
      <argument name="retVariable" value="qMyPeople"/>
      <argument name="filterby" value="name" />
      <argument name="filterstring" value="searchfield"/>
   </message>
What is going on here? lots of event-ing! , we have changed the cfif statement to include the line event.valueExists(event.getArgument("filterstring")), which gets the the string "searchfield" from our arguments, and then checks to see if we have a form or url variable named "searchfield". If there is one, in the cfinvokeargument, we then go and get that variable and pass it to the function. Now you are cooking with gas!

Comments

Mark Drew

Mark Drew wrote on 09/22/08 11:13 AM

Cheers for that Ray! Is this better?
Raymond Camden

Raymond Camden wrote on 09/22/08 11:13 AM

Thank you - my eyes are happy. :)
Jamie Jackson

Jamie Jackson wrote on 09/22/08 11:14 AM

I really like this idea that you mentioned:

cfset event.setValue(event.getArgument(&quot;retVariable&quot;, &quot;qPeople&quot;), r_qPeople)

It's a pain to have to go all the way to a controller CFC to figure out the name of the event var that a given message generates. Further it's conceivable that you could run into variable naming collisions while adding functionality to a large, existing, application.

Therefore, having the event var name declared in the controller makes perfect sense to me.

Do you personally add that dynamic setter universally to all your controller functions that inject event vars? I'm considering making this line standard in my controllers....
Will Tomlinson

Will Tomlinson wrote on 09/22/08 11:14 AM

Thanks so much Mark! I know I'm a bit late to your post, but it STILL helped me as I work on my first MG app.

My functionality was better-suited to Config variables though. I started with your argument examples, then moved them to my Coldspring.xml file, in an AppConfig entry key.

Going thru this process helps you understand how much simpler things become when you use MVC like this.

Thanks again guy! :)

Write your comment



(it will not be displayed)







Search Archives

Contribute


Twitter Updates

Categories

coldfusion cfeclipse personal apple cfconferences webdev model-glue ukcfug blogging cfunited coldspring presentations adobe scotch on the rocks cfobjective lost reactor jobs flex eclipse ajax model-glue frameworks max reference google podcasting fusebox ask md spam railo eventvalidation donations tattoo snipex podcast music microsoft fusiondebug flying blue dragon air wishlist tips rant open bluedragon java graphic novels funny eventguard derby blog aptana apple xml webservices transfer tashr subversion spry regex quack pownce ooops mvc metrics jquery itunes hosting groovy gadgets flash firefox doh! directing development coldfusioncamp codeshare cfug cfonwheels cfdevcon bolt apollo

Monthly Archives