Menu

As simple as possible, as complex as necessary

Using <cfproperty> to create default CFC property values

16 May 2011

My current ORM learnings have brought me into contact with cfproperty, a tag I've never previously needed since its capabilities pre-CF9 were limited. To create usable properties in components (as in properties v. methods) you set them and their default values directly in the variables scope (or possibly in a variables.instance struct so you can refer to them as a group).

// Cat.cfc
<cfcomponent displayname="Cat">
<cfscript>	
	function init()
	{
		variables.instance =	
		{
			name=""
			,type="tabby"
		}
		return this;
	}
</cfscript>
</cfcomponent>

Getting better: better getting (and setting)

In CF9, cfproperty is much more useful, but it still won't always do what its name and attributes suggest: i.e. define and set default values for your CFC properties.

What it will do now is automatically generate a synthesized (a.k.a implicit) setter and getter for each property if you so choose by adding the accessors attribute to the component.

<cfcomponent displayname="Cat" accessors="true">
<cfproperty name="name" default="">
<cfproperty name="type" default="Tabby">
<cfscript>	
	function init()
	{
		return this;
	}
</cfscript>
</cfcomponent>

This means we can call getName() and setName("value") without having to physically code these methods in the cfc (or write your own generic getter/setters using onMissingMethod() in Application.cfc)

Not quite there

All very nice, except that if we invoke my CF9 Cat.cfc as follows and try and use the auto getters...

myCat = new Cat();
WriteDump( myCat.getName() );
WriteDump( myCat.getType() );

...we get:

CFDump showing Undefined Undefined

The auto-generated get methods do exist (otherwise we'd have got an error), but the properties are apparently undefined, despite having defined them with cfproperty. Why aren't we seeing the default values set in the tags?

The problem seems to be that CF doesn't put the properties into the variables scope until each one is assigned a value, as explained in this post by CiarĂ¡n Archer, and reported as a bug by Luis Majano. In other words we can only get it if we first set it.

myCat = new Cat();
myCat.setName( "Tibbles" );
WriteDump( myCat.getName() );

The above outputs "Tibbles" as you'd expect.

Adobe have partially documented this when they say:

Features of properties with setter and getter methods include the following [...]
  • [...]The default attribute has no effect on the property and does not set an initial property value.

But the whole point of defaults is to make sure values exist whether or not they are set, and not being able to rely on cfproperty for this means we're going to have to keep initialising our properties the old way.

But wait...

Except that... with the ORM app I'm currently playing with I noticed that the cfproperty defaults were being set as expected.

So I thought I'd try making my test Cat pretend that it was part of an ORM application, even though it was a completely standalone CFC with no database, no Application.cfc and therefore no ORM settings. How? By just setting the persistent attribute on the component.

<cfcomponent displayname="Cat" persistent="true" accessors="true">
<cfproperty name="name" default="">
<cfproperty name="type" default="Tabby">
<cfscript>	
	function init()
	{
		return this;
	}
</cfscript>
</cfcomponent>

Now when we re-run the code with no setters...

myCat = new Cat();
WriteDump( myCat.getName() );
WriteDump( myCat.getType() );
Cat lying on a laptop
Just pretending to be an ORM Cat (real name not Tibbles)

...we get our default values: [empty string] Tabby

I'm not sure what else happens behind the scenes when you use the persistent attribute, but I'm using it in all the model objects in my non-ORM-enabled blogging app, and so far I've noticed no untoward effects on performance or the database.

The cat seems pretty relaxed about it too.

Posted on . Updated

Comments

  • Formatting comments: See this list of formatting tags you can use in your comments.
  • Want to paste code? Enclose within <pre><code> tags for syntax higlighting and better formatting and if possible use script. If your code includes "self-closing" tags, such as <cfargument>, you must add an explicit closing tag, otherwise it is likely to be mangled by the Disqus parser.
Back to the top