So what does Coldspring do, anyways? We know by now that it's an Inversion of Control (IoC) framework. We also know that it helps us manage dependencies between objets. And yet, we're not quite sure what that means exactly yet. To help demonstrate the power of Coldspring, I've prepared a simple example.

To show what Coldspring can do, we need objects. For the purpose of our example, we're going to use a dummy Person model. Our model needs properties, so let's try and see how we can define a person. A person generally has a couple of generic traits: name, birth date, sex (*giggle*), height, weight, and so on. Generally we'd need a way to save all of our people, so we'll have to think of a table that can hold all of them:

person_id	integer
name		varchar
birth date	datetime
sex		char
height		smallint
weigth		smallint
[...]

Simple stuff. Now, our generic template for most of our templates will require four objects: a bean, a service object, a gateway and a DAO.

Bean
Picture the bean as the actual representation of our object. Through the bean we can set and get it's properties and make sure that it's valid in it's current state.
Service object
This is generally who we're going to be talking to. We'll ask our service object for an instanciated bean of our person model; we'll ask our service object to retrieve a series of beans; we'll ask our service object to save our bean in the DB; etc. The service object then handles the request and sends it to the appropriate object for processing.
Gateway
The gateway serves as the proxy to the database for multi-user queries. Generally the gateway will be used to select a list of model objects.
DAO
The DAO, or Data Access Object, is the proxy for CRUD (Create, Read, Update, Delete) operations on an object. The service object will use the DAO to perform CRUD operations on the model.

Real-life update 1: Electrical problems on the train. It's hot as hell but I get more time to write :P.

Using a tool like cfcgenerator can save you alot of time when writing your domain model. It will take a table and generate all four objects for you.

If we look at what a tool like cfcgenerator generates for us, we'll notice four new .cfcs. Here they are with the interesting parts outlined:

Real-life update 2: Turns out a cable snapped and it'll take at least half an hour to fix. Ironically I'm 10 minutes' walk away from my parents house.

person.cfc
--------------
init()
setPerson_id()
setName()
[...]
getPerson_id()
getName()
[...]

personService.cfc -------------- init() personGateway personGateway personDAO personDAO getPerson() getPersons() savePerson() [...]

personGateway.cfc -------------- init() dsn string getPersonsByAttribute() [...]

personDAO.cfc init() dsn string create() read() update() delete() [...]

As you can see I didn't list out all the methods: just enough to show what these objects actually do and what they depend on. Notice that personService object needs to have the personGateway and personDAO objects passed in when inited. Also, both the personGateway and personDAO objects require a dsn string be passed in when inited. Without IoC, here's how that would look like:

view plain print about
1<cfscript>
2dsn = "mydsn";
3
4// remember we have a squash mapping that points to our install location
5
oPersonGateway = createObject(
6        "component",
7        "squash.model.personGateway"
8    ).init( dsn=dsn );
9
10oPersonDAO = createObject(
11        "component",
12        "squash.model.personDAO"
13    ).init( dsn=dsn );
14
15oPersonService = createObject(
16        "component",
17        "squash.model.personService"
18    ).init(
19        personGateway=oPersonGateway,
20        personDAO = oPersonDAO
21    );
22
</cfscript>

That's alot of code! Enough to turn anyone away from using object-oriented programming. With Coldspring, however, things get much easier.

view plain print about
1<cfset oPersonService = getPlugin( "ioc" ).getBean( "personService" ) />

There's a plugin within ColdBox called "ioc". This is basically what talks to Coldspring and makes all the magic work. Using the plugin's getBean method we ask Coldspring to return the personService object instantiated. It takes care of resolving any and all dependencies.

But how does Coldspring know how to resolve these dependencies? In our config folder there's a coldspring.xml.cfm file. Within that file we define our objects (beans) and declare how they depend on each other. When cfcgenerator generates all our model code, it also generates a coldspring definition file for each of the objects generated. We just need to merge them all together and put them in our own file:

view plain print about
1<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
2<beans>
3
4    <bean id="personDAO" class="squash.model.personDAO">
5        <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
6    </bean>
7    <bean id="personGateway" class="squash.model.personGateway">
8        <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
9    </bean>
10    <bean id="personService" class="squash.model.personService">
11        <constructor-arg name="personDAO">
12            <ref bean="personDAO"/>
13        </constructor-arg>
14        <constructor-arg name="personGateway">
15            <ref bean="personGateway"/>
16        </constructor-arg>
17    </bean>
18
19</beans>

Each "bean" represents an object in our domain model. We give them an ID so they can be referenced elsewhere in the config file as well as by the getBean method. The class attribute points to the actual .cfc file.

Within each bean you can notice that there are constructor-arg nodes. These are arguments that will be passed in to the init method of each object. For both the personGateway and personDAO nodes the single constructor-arg is the dsn, which in this case is a reference to a ColdBox setting variable. Anytime you enclose a value with ${}, ColdBox will attempt to pass in a value from the YourSettings node in the coldbox.xml.cfm.

The personService bean is slightly different. Instead of having a value node within it's constructor-args, it has a ref node. This is how you tell Coldspring that a bean depends on another (or others). You pass in the ID of the bean and Coldspring knows that it will need to resolve their dependencies and inject them into the bean requested before sending it back.

You might also notice that there's nothing in there relating to the person object. The reason is that generally we won't need to access the person bean directly: the service object will provide it for us. Since it isn't a dependancy of anything, and that we won't be asking Coldspring for it, we can leave it out.

And that's the end of my eventful ride to work. We won't be needing the person model for SQUASH so we won't be seeing it again. Tomorrow, if nothing goes wrong (*knocks on wood*), we should be looking at some actual SQUASH code.