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...


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...
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.