Transfer ORM

When developing an Object Oriented web based application, it is normal to have a database with relational tables and a series of objects that represent that data. Often, the amount of time and effort it takes to manually map these objects back and forth from a database is large, and can be very costly.

Object Relational Mappers (ORM) were developed to cut down the amount of time this process takes, and automate the translation between a relational database and an Object Oriented system.

Transfer ORM's main focus is to automate the repetitive tasks of creating the SQL and custom CFCs that are often required when developing a ColdFusion application. Through a central configuration file Transfer knows how to generate objects, and how to manage them and their relationships back to the database.

Setting up Fusebox for Transfer

To get Transfer setup you need to initilise the Transfer factory, you do this using the initialize verb. The best place to do this is in the appinit section of fusebox.xml.cfm as this is called when you start your app (it's like the onApplicationStart function in application.cfm). Within this function I call a fuseaction in my model circuit:

...
<appinit>
<fuseaction action="m.transferSetup" />
</appinit>
...

Then inside the model circuit I have this fuseaction

...
<circuit access="public" xmlns:tr="transfer/">
<fuseaction name="transferSetup">
<tr:init
datasource="/config/datasource.xml.cfm"
configuration="/config/transfer.xml.cfm"
definitions="/model/transferData" />
</fuseaction>
...

What we have just done:

  1. We're declaring the namespace for the transfer lexicons
  2. tr:init - this calls the initialize verb from the transfer lexicon folder to get Transfer setup.
  3. datasource="/config/datasource.xml.cfm" - this is telling Transfer where to find the datasource config file.
  4. configuration="/config/transfer.xml.cfm" - this is telling Transfer where to find the Transfer config file.
  5. definitions="/model/transferData" - this tells transfer where to put it's generated code

One you run this code Transfer is up and running. Thats it, nothing else left to do. You now have access to all of Transfers features.

Transfer Configuration

Next you'll want to configure Transfer to tell it how all the tables are setup and related (we'll take a simple example here):

<?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="/transfer/resources/xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<objectDefinitions>
<package name="user">
<object name="user" table="tblUser">
<!-- generate tells the DB if we need to create a unique key for inserts -->
<id name="userID" type="numeric" generate="false" />
<property name="contactName" type="string" />
<property name="userPassword" type="string" />
<property name="email" type="string" column="emailAddress" />
<property name="userTypeID" type="string" />
<property name="lastLogin" type="date" />
<property name="live" type="boolean" />
<onetomany name="address">
<link column="userID" to="address.address" />
</manytoone>
</object>
</package>

<package name="address">
<object name="address" table="tblAddress">
<id name="addressID" type="numeric" />
<property name="address1" type="string" column="address1" />
<property name="address2" type="string" column="address2" />
<property name="address3" type="string" column="address3" />
<property name="town" type="string" column="town" />
<property name="country" type="string" column="country" />
<property name="postCode" type="string" column="postCode" />
<property name="addressTypeID" type="numeric" column="addressTypeID" />
<property name="refID" type="numeric" column="refID" />
<property name="live" type="boolean" column="live" />
<property name="county" type="string" column="county" />
<manytoone name="addressType">
<link column="addressTypeID" to="address.addressType" />
</manytoone>
</object>

<object name="addressType" table="tblAddressType">
<id name="addressTypeID" type="numeric" />
<property name="addressType" type="string" column="addressType" />
</object>
</package>
</objectDefinitions>
</transfer>

What we have just done:

  1. <objectDefinitions> - this just declares that you're starting you object definitions
  2. <package name="user"> - this is a neat way to group your objects together (you don't require this)
  3. <object name="user" table="tblUser"> - this setup your object and gives it its name and tells it what table it refers to
  4. <id ...- this is your primary key on the table
  5. <property ... - we use property to list the table columns you want to return. Note you can use any name as long as you tell the property what column to use i.e. <property name="email" type="string" column="emailAddress" />
  6. <onetomany name="address"> - this is telling Transfer that I want to join my user table to my address table, where the I have One user and Many Address
  7. <link column="userID" to="address.address" /> - this is what I join the tables on. I'm telling transfer to look at the address object in the address package and join on userID.

Fusebox Transfer Verbs

Okay so you now have you Transfer factory created and you have Transfer set up, next you'll want to get data from Transfer.

Lets start with looking at what you can do with the fusebox lexicons:

  • init - self explanitory
  • parameter - Allows you to pass in variables to the read verb
  • read - Allows you to get a single record
  • list - Allows you to get a list of records
  • save - Saves records
  • delete - Deletes records
  • populate - Populates a Transfer object with query data

For more details on Fusebox Transfer Verbs, click here

Now we know what lexicons we can use fusebox lets look at a fuseaction (in our model) using the read verb:

<fuseaction name="checkLogin">
<tr:read object="user.user" bean="checkLogin">
<tr:parameter name="email" value="#attributes.email#" />
<tr:parameter name="userPassword" value="#attributes.password#" />
<tr:parameter name="live" value="1" />
</tr:read>
</fuseaction>

In this fuseaction we are asking Transfer to get the user object from the user package setup in the Transfer configuration file. We pass in a email address and password form a form this read. We then reference the result using the bean name, in this case 'checkLogin'.

So let say we call the checkLogin fuseaction from our controller:

<fuseaction name="checkLogin">
<do action="m.checkLogin" />
<if condition="(checkLogin.getUserID())">
<true>
<do action="vendor-m.setSession" />
<relocate url="#request.myself##xfa.myAccount#" />
</true>
<false>
<relocate url="#request.myself##xfa.login#&loginError=1" />
</false>
</if>
</fuseaction>

Here we have called our checkLogin fuseaction from our model circuit, we then look at the returned bean 'checkLogin'. If it can find a userID then Transfer has found a record. We're happy with this so we setup the session variables and relocate to the user to the account area.

If the userID can't be found then there has been an error with the login so we redirect the user back to the login page.

But, where did getUserID() come from?

Well as Transfer knows that my table has a userID field, it cleverly goes of and creates getters and setters for that field (as well as any other table field you setup in the config file). We then simple call these getters and setters prefixing the tableField with get or set. How cool is that. Now we've got that clear did you notice we've not written one line of SQL?

TQL in Fusebox

With Transfer setup and working inside your Fusebox application, you can use its built in TQL query language. For more information, click here

External Links