Thursday, May 01, 2003

kwfu: ['relocated']

I've moved!


I've finally got round to setting up my blog on a CF server.

The new url is http://www.spike.org.uk/fu/blog.cfm

I'll be gradually moving the content from here to the new site, so update your bookmarks Nachos!

Spike

Thursday, April 10, 2003

kwfu: ['farcry','cms']

Just finished a couple of hectic days working on the next release of FarCry. If you don't know what FarCry is, I suggest you get on down to the website and have a look at it.

http://farcry.daemon.com.au

It's a complete enterprise content management system built in CFMX built by the guys at Daemon in Sydney Australia. It supports many of the things that were available in Spectra, but it's FREE!!!

100% Open source goodness!

You can go download it from here, or you can go and look at the demo site here. If you do go to the demo site, make sure you login and check out the admin interface. That's the same interface you get from a fresh install.

If you're currently running Spectra and are looking for something to migrate to, I'd definitely suggest you download it and take a look. It's already been used to migrate a few sites in Australia. They aren't small sites either. Roche Pharmaceuticals Asia Pacific intranet and Integral Energy

It's currently being labelled as version 1, but a lot of the code's been in use for the last 4 years in various different projects.

Definitely worth a look

Spike

Wednesday, February 26, 2003

kwfu: ['cfproperty','cfc']

A long time ago I promised to put some more info in my blog about CFCs. Well, now I'm coming good on that promise.

You may be wondering exactly what use the <cfproperty> tag is. Well, there are at least 2 uses for it. I was intending to put them both into this post, but I got a bit overexuberant with the examples, so I'll split it into 2 blog posts.

1. Providing static data for component instances


When you create a component instance, you can use the getMetaData() function to retrieve all the data that is defined in the <cfproperty> tag. You also get information about the attributes in the <cfcomponent> and <cffunction> tags, but I digress. As an example:

Say you have employee.cfc that contains employee information.

<cfcomponent displayname="employee">
<cfproperty name="minage" type="numeric" value="18">
<cfproperty name="maxage" type="numeric" value="65">

<cffunction name="getEmployee" access="public">
<!--- Code to get employee info goes here --->
</cffunction>

<!--- More methods go here --->

</cfcomponent>

You can create an instance of this component as follows:

<cfscript>
emp = createObject('component','employee');
</cfscript>

You can then retrieve and view the data defined in the cfproperty tags like this:

<cfdump var="#getMetaData(emp)#">

If you look at the output from the <cfdump> tag, you will notice that it contains all the attributes of all the <cfcomponent>, ;<cfproperty> and <cffunction> tags in the component. This is true even if you define your own attributes in those tags. This can be particularly useful for defining information about how component instances and properties of those instances should be treated. You could, for example, create an editHandler attribute for the <cfcomponent> tag that defined what file should be used to edit instances of that component. You might also use this to determine default values for the properties of your component instance. The <cfproperty> tag will not create the properties for you, but you can use the metadata to initialize them yourself.

Something like this:

<cfcomponent displayname="employee">
<cfproperty name="minage" type="numeric" value="18">
<cfproperty name="maxage" type="numeric" value="65">

<cfscript>
init();
</cfscript>

<cffunction name="init" access="private">
<cfset md = getMetaData(this)>
<cfloop from="1" to="#arrayLen(md.properties)#" index="i">
<cfset this[md.properties[i].name] = md.properties[i].value>
</cfloop>
</cffunction>

<!--- More methods go here --->

</cfcomponent>

The following code will allow you to see how this works:

<cfscript>
emp = createObject('component','employee');
</cfscript>
<cfdump var="#emp#">

This is a pretty useful feature, but you need to be careful about the time that getMetaData() can take to return data in complex component hierarchies. You should also be aware that you could quite easily do this instead:

<cfcomponent displayname="employee">

<cfscript>
init();
</cfscript>

<cffunction name="init" access="private">
<cfset md = getMetaData(this)>
<cfset this.minage = 18>
<cfset this.maxage = 65>
</cffunction>

<!--- More methods go here --->

</cfcomponent>

The downside of this way of doing things is that when you use the component browser you will not see what the default values will be in the documentation code.

Hopefully all that made sense, next time <cfproperty> and webservices.

Spike

Sunday, February 23, 2003

kwfu: ['travelling']

Well, it's been a long time since my last post and a lot of things have happened in that time...

I've left my job in the Netherlands, been ski-ing in the French Alps for Christmas and New Year, spent a few weeks travelling across Canada, and got to Australia in time to speak at MXDU in Sydney on 19th and 20th of February. The conference was great and many thanks go out to the speakers and organizers who made it as good as it was. Special thanks to Geoff Bowers and the team from Daemon who had all the speakers over for a good ole aussie barbie on Friday night.

I'm planning on hanging around in Australia for a few months before moving on to Asia for a while. After that, who knows, but it might well involve getting in touch with the Australian authorities for a slightly more permanent visa.

Spike

Friday, November 01, 2002

kwfu: ['english','OT']
I got this in an email from an old college friend of mine today:

*snip*
We have a logo that says "Research And Development", but the boss wanted to put a hyphen between the words Research and And and And and Development in my Research-And-Development logo.

I said that the sentence 'I want to put a hyphen between the words Research and And and And and Development in my Research-And-Development logo' would have been clearer if quotation marks had been placed before Research, and between Research and and, and and and And, and And and and, and and and And, and And and and, and and and Development, as well as after Development!
*snip*

Good old english

Spike


Thursday, October 17, 2002

kwfu: ['UI','architecture','slashdot']

An interesting thread about UI architecture popped up on slashdot today. Qute a few of the responses don't answer the question, but a lot of them should be interesting to people building complex systems with CFMX and Flash.

Spike

Wednesday, October 16, 2002

kwfu: ['CF','Link','advanced']
Stumbled across this page on the Macromedia website today. Very useful set of articles on Advanced ColdFusion development all in the same place.

Spike
kwfu: ['super','cfc','extends']

Continuing the cfc theme of the last couple of weeks, here's a little trick that might be useful to some people.

Suppose we have a cfc called base.cfc that has a method called init(). The purpose of init() is to set up some initial data and parameters for the component. The use of init() to initialize an object is common in the Java world, so it makes some sort of sense to follow the same idea in components.

Now, suppose we have a cfc called extends.cfc that extends base.cfc. Extends.cfc also has a method called init() to initialize it's data. This could cause a problem because extends.init() will override the init() function declared in base.cfc. In the Java world, we would use the super keyword to access the init() method in the parent component. Unfortunately the super keyword doesn't work with components so there isn't an easy way to call a method that has been overridden by an extending component.

The little trick that I'm about to show you relies on the fact that you can attach methods to a component after it has been instantiated. If the data in the un-named scope is put into a structure, you can easily access all the data in that structure as long as you know what it is called. For the purposes of this example I'm going to use 'protected' as the name of my structure.

Take the following code:

base.cfc
<cfcomponent hint="base component">


<cffunction name="init">
<!--- Create a structure called protected in the un-named scope.
This structure will act as a pseudo scope for component data --->
<cfset protected = structNew()>
<!--- Add some data to the protected structure --->
<cfset protected.a = "value of a">
<cfset protected.b = "value of b">
</cffunction>


</cfcomponent>

Extends.cfc
<cfcomponent hint="extending component" extends="base">



<!--- This function is used to get the data from the super object.
It could be attached to any component instance to access the data in the 'protected' scope --->
<cffunction name="getProtected" access="private">
<cfif isDefined('protected')>
<cfreturn protected>
</cfif>
</cffunction>

<cffunction name="init">
<!--- Create a structure called protected in the un-named scope.
This structure will act as a pseudo scope for component data --->
<cfset protected = structNew()>

<!--- Create an object that points to the ancestor of this component --->
<cfset super = createObject('component','base')>

<!--- Attach the getProtected() method to our super component --->
<cfset super.getProtected = getProtected>

<!--- Fire the init() method of the ancestor --->
<cfset super.init()>

<!--- Make the private data from the ancestor component available to this component --->
<cfset super.protected = super.getProtected()>

<!--- Add the protected data from the ancestor to this component's protected structure --->
<cfset structAppend(protected,super.protected,false)>

<!--- Add some data to the local protected structure --->
<cfset protected.c = "value of c">
<cfset protected.d = "value of d">
</cffunction>

<!--- This function returns the protected data from the current component instance --->
<cffunction name="getAll">
<cfreturn protected>
</cffunction>

</cfcomponent>

invoke.cfm
<cfset obj = createObject('component','extends')>
<cfset obj.init()>
<cfdump var="#obj.getAll()#">

Now we've managed to create the functionality of a super.init() in a CFC.

The caveat to this is that we're not really duplicating what you get with the super keyword in Java. The important difference is that in Java we wouldn't be creating a separate object instance to access the method declared in the parent, the method would be running from within the context of the extending component. This is important if the method relies in any way on the data that exists in the instance.

For example:

You have a generic shopping cart component called cart.cfc that has a method called sum() that calculates the total cost for the items in a cart. Say bargain.cfc extends cart.cfc and has a method called sum() that calls the sum() method in the cart.cfc, then applies a discount of x% to the result. If the cart items are stored in the un-named scope of bargain.cfc, the sum() method in cart.cfc will not have access to them, and so will most likely return ZERO as the total cost for the items in the cart!

Clearly this is not desireable, so although we can get some of the way to emulating super in Java, it doesn't get us all the way there.

Spike