Setting up and using Transfer within fusebox via the Transfer lexicons
Setting up Transfer within fusebox via the Transfer lexicons
After my previous post where I cover Setting up Coldspring within fusebox via the CS lexicons I've now just got Transfer working with the Transfer lexicons.
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:
<fuseaction action="m.transferSetup" /> </appinit>
<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>
So what's heppening here:
<circuit access="public" xmlns:tr="transfer/"> - we're declaring the
namespace for the transfer lexicons
tr:init - this calls the initialize verb from the transfer
lexicon folder to get Transfer setup.
datasource="/config/datasource.xml.cfm" - this is telling Transfer where to find the datasource config file.
configuration="/config/transfer.xml.cfm" - this is telling Transfer where to find the Transfer config file.
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.
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):
<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>
So what's the deal here:
<objectDefinitions> - this just declares that you're
starting you object definitions
<package name="user"> - this is a neat way
to group your objects together (you don't require this)
<object name="user" table="tblUser"> -
this setup your object and gives it its name and tells it what table it refers
to
<id ...- this is your primary key on the table
<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" />
<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
<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.
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 - we've covered this already above
parameter - this allows you to pass in variables to the read verb
read - this allows you to get a single record
list - this allows you to get a list
of records
save - Save records
delete - delete records
populate - Populates
a Transfer object with query data
Okay so now we know what lexicons we can use fusebox lets look at a fuseaction (in our model) using the read verb:
<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>
So let say we call the checkLogin fuseaction from our controller:
<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.
Wait a second, 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?
I can't recommend downloading and playing with it enough!





I've added this article to the 'getting started' documentation section under 'framework tutorials' that will be released with the next version.
Thanks!
Minor typo - xmlns:tf="transfer/" should be xmlns:tr="transfer/"
@dickbob AKA Eagle eyes ;) - many thanks, I've updated it.
One thing I'm not sure about and I don't know if you have an opinion on it is, how do I handle an app with two DSN's? I realise that I can have more than one datasource/configuration file and definitions location but what about the TransferFactory created by the init verb? I assume that I should have a Factory per DSN/database? Should the lexicons be extended to support an optional Factory name? Should I really be directing these issues to the author (Sean) of the lexicons or having a go at posting an update myself?
Or am I just plain wrong! :-)
About time ;o)
Mark
<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>
but I don't see where you get the various files.
/config/datasource.xml.cfm"
/config/transfer.xml.cfm"
/model/transferData
Thanks.
I've just started messing around with Fusebox and my starting point on the road to understanding Transfer has been through your great tutorials.
I'm really starting to see the potential of this, the first example I setup removed 3 cfcs full of SQL straight away, but there is something about having the start of my SQL management inside the Fusebox that doesn't sit comfortably with me.
Maybe it's my lack of understanding but if I was looking to use Transfer for my DB management layer then I would expect to see it happening within CF files within my model/controller rather than right inside the circuits themselves.
I guess what I'm trying to say is what would be the advantage of this way over a more "traditional" approach?