Halhelms
SIGN UP FOR MY NEWSLETTER

www.savorgold.com is top on wow gold and runescape gold and World of Warcraft gold provider list for trusted services. Their reputation seems to growing by the minute, which isn't surprising because they are one of the safest sellers of Gold. Delivery speed and customer service are very good. They aslo are giving some bonus items depending on the amount of gold you purchase.

 
 
Halhelms

Recent Comments

Recent Entries

RSS

Learning ColdBox: II.V : Wherein I Ask for Expert Help...

With the (very) basics behind, I'm ready to try my hand at a CRUD application. (Hopefully, that won't prove to be prophetically named...) But before I start, I want to explain how I do things presently -- and ask expert ColdBoxers for some guidance as to what should be changed to best use ColdBox.

Much of the way I write ColdFusion has been heavily influenced by working with Rails and jQuery. So, while I welcome the built-in getX and setX methods for every property, X, that CF9 offers, I much prefer jQuery's x() as a getter and x('some value') as a setter.

I begin by creating an ActiveRecordModel object that all model objects extend. To get the desired jQuery-type getters and setters, I use onMissingMethod:

   public function onMissingMethod( 
      string missingMethodName, 
      struct missingMethodArguments) 
   {
      // is this a call to a getter/setter?
      if ( isProperty ( arguments.missingMethodName ) ) {
         if ( StructCount( arguments.missingMethodArguments ) ) {
            variables[ arguments.missingMethodName ] = arguments.missingMethodArguments[ 1 ];
            return this;
         } else {
            return variables[ arguments.missingMethodName ];
         }
      } 
   }

Now, given object obj with properties firstName and lastName, I can use this syntax:

// what's my first name?
obj.firstName()

// let me change that to "Hal" obj.firstName( 'Hal' )

// this won't work (it shouldn't) because color isn't a defined cfproperty obj.color( 'blue' );

I would also like to be able to do a bulk update on an object's properties: thus the updateAttributes method:

obj.updateAttributes( { firstName = 'Hal', lastName = 'Helms', color = 'blue'} );

Again, only valid pre-defined cfproperties will be effected.

Having a built-in ORM available to ColdFusion is excellent. I was initially very skeptical of Adobe's commitment to do this well, but I'm happy to eat my words. (There are some smallish drawbacks, but overall an excellent job.)

I got used to some nice convenience methods in Rails and wanted to have these available to me in ColdFusion. So, in my same ActiveRecordModel abstract class, I have added the ones I find the most frequent use for:

  • where
  • first
  • last
  • find
  • findByX (where X is a valid cfproperty)
  • save

I also provided an invoke object that will instantiate a new ORM-enabled model object. (In the case where no such object can be created, it returns a Java null object.)

Here is a test.cfm file to show these in use:

   //Create Immanuel Kant
   ik = invoke.Philosopher();
   ik.firstName( 'Immanuel' );
   ik.lastName( 'Kant' );
   ik.born( 1724 );
   ik.died( 1804 );
   ik.influence( 5 );
   ik.sunniness( 2 );
   ik.comprehensiveness( 3 );
   ik.save();
   
   writeDump( ik );
   
   //A little too much work: use upDateAttributes
   
   //Create Arthur Schopenhauer
   as = invoke.Philosopher().updateAttributes( 
      {
         firstName         = 'Arthur',
         lastName          = 'Schopenhauer',
         born              = 1788,
         died              = 1860,
         sunniness         = 1,
         comprehensiveness = 5,
         influence         = 2  
      }
   ).save();

writeDump( as ); // A more modern philosopher... ap = invoke.Philosopher().updateAttributes( { firstName = 'Alvin', lastName = 'Plantinga', born = 1932, sunniness = 4, comprehensiveness = 4, influence = 2 } ).save(); writeDump( ap );

// most influential philosophers? mostInfluential = invoke.Philosopher().where( 'influence > 4' ); for ( philosopher in mostInfluential ) { writeOutput( philosopher.lastName() & ' still has enormous influence. <br />' ); } // where's Alvin? plantinga = invoke.Philosopher().findByLastName( 'Plantinga' )[1]; writeOutput( plantinga.firstName() & ' in the house <br />' ); // gloomiest philosopher? gloomiest = invoke.Philosopher().first( 'sunniness < 3 ORDER BY sunniness ASC' ); writeDump( gloomiest );

And the results:

BTW, the invoke variable is a simple helper class that returns an instance of the type requested of it (Philosopher in this case).

So, in poking about the documentation, it appears that ColdBox has some very similar features in the BaseORMService. Unlike Rails, it assumes a service layer that operates with model objects. Since working with Rails, I enjoy the freedom of having an ActiveRecord abstract class that handles the interactions with the database without involving a service layer.

Question: if I go down the Rails-like route, am I going to run into problems because of assumptions that ColdBox has (that I don't presently know about)? Any advice gratefully accepted...

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Richard Herbert's Gravatar There's nothing wrong of course with how you prefer to code. It's your personal style preference. Nothing really to do with ColdBox.

Whilst you may not like using a service layer, ColdBox offers may time saving features with BaseORMService as you've seen. The "cheapest" why to get access to this is to use a VirtualEntityService which you can inject into your handler by using...

property name="PhilosopherService" inject="entityService:Philosopher";

If you ever need more service methods than Luis provides you can then create your own actual Service object, which can then extend the VirtualEntityService, for your particular needs.

http://wiki.coldbox.org/wiki/Extras:VirtualEntityS...
http://blog.coldbox.org/post.cfm/baseormservice-vi...
# Posted By Richard Herbert | 4/4/11 6:16 AM
Luis majano's Gravatar Hal, I like your approach. We had discussions in the team to provide an active record base class based on our virtual entity service class for 3.1. Which in all reality it might be e virtual entity class anyways. You can easily leverage what you need from the virtual entity class much how Richard mentioned. Also, maybe sone of those cool methods can be imported into the core for 3.1
# Posted By Luis majano | 4/4/11 1:46 PM
Hal Helms's Gravatar @Richard @Luis Wonderful, thanks. I'm enjoying learning ColdBox.
# Posted By Hal Helms | 4/4/11 2:25 PM
Julian Halliwell's Gravatar Hal, just to say I've also been a big fan of the jQuery getter/setter style using onMissingMethod ever since you first suggested it a few years ago (in comments on someone's blog - do you remember whose?)

It makes code seem so much more readable and clear without all those "get"s and "set"s everywhere. "Syntactic sugar", as you described it.
# Posted By Julian Halliwell | 4/6/11 5:58 AM
Hal Helms's Gravatar @Julian: I'm glad you find it helpful. I don't remember whose blog it was.
# Posted By Hal Helms | 4/6/11 6:06 AM
Julian Halliwell's Gravatar @Hal: Tracked it down to some obscure, infrequent blogger by the name Ben Nadel: http://www.bennadel.com/blog/1153-Fusion-Authority...
# Posted By Julian Halliwell | 4/6/11 7:50 AM
Hal Helms's Gravatar @Julian What a small world! I know that guy, Jim Nadel, quite well. I've tried to encourage him to blog more, but he's all like "But what would I write about?" Sad, really...
# Posted By Hal Helms | 4/6/11 6:17 PM
 
   
Clicky Web Analytics