I'm a bit late in finishing up the next part of my Transfer series (I blame Fable 2 - it kept me up till 2AM!), but if you remember the last entry, I discussed how to create, update (save), delete, and get data using Transfer. I also showed how Transfer creates a CFC based on the XML definition we created for our Employees. This is really everything we need to build a simple employee editor, except for one piece - getting a list of employees.

I alluded to the fact that Transfer had many ways of getting data. Yesterday's post showed the simple get() method. Today we will look at list() and it's variants.

The list() method takes a class (the name of our data type) and an optional column to sort by. You can also pass a third argument that specifies if the sort should be an ascending sort or a descending sort. This one tends to trip me up. Instead of passing "asc" or "desc", you pass a true or false. True implies ascending and false means descending. (There is a four argument as well but we won't worry about that now.)

So all in all, to get a list of employees it takes all of one call.

<cfset employees = application.transfer.list("employee", "lastname")>

Simple, right? The list method returns a query of employees, not an array of Employee objects. So by now we easily have enough to build a tool to let us administrate employees. For this demo, I decided to put these files within an admin folder, but didn't bother to add any security. In case it isn't obvious, you wouldn't do that in production. I began with employees.cfm:

<cfif structKeyExists(url, "delete")> <cfset employee = application.transfer.get("employee", url.delete)> <cfset application.transfer.delete(employee)> </cfif>

<cfset employees = application.transfer.list("employee", "lastname")>

<h2>Employees</h2>

<cfif employees.recordCount> <table border="1"> <tr> <th>Name</th> <th>Email</th> <th> </th> </tr> <cfoutput query="employees"> <tr> <td><a href="employee.cfm?id=#id#">#lastname#, #firstname#</a></td> <td>#email#</td> <td><a href="employees.cfm?delete=#id#">Delete</a></td> </tr> </cfoutput> </table> <cfelse> <p> There are no employees now. </p> </cfif>

<p> <a href="employee.cfm">Add Employee</a> </p>

This follows my typical admin pattern of 'Get the crap, make a table, and link to edit or delete.' You can see the list command and the table that outputs each employee. I link to employee.cfm for editing, and back to myself for deleting. If you remember from yesterday, you have to get the TransferObject before you delete via Transfer.

Now let's look at employee.cfm, the main editor for employees:

<cfparam name="url.id" default="0">

<cfif url.id is 0> <cfset employee = application.transfer.new("employee")> <cfelse> <cfset employee = application.transfer.get("employee", url.id)> </cfif>

<!--- param values ---> <cfparam name="form.firstname" default="#employee.getFirstName()#"> <cfparam name="form.lastname" default="#employee.getLastName()#"> <cfparam name="form.dob" default="#employee.getDOB()#"> <cfparam name="form.email" default="#employee.getEmail()#"> <cfparam name="form.phone" default="#employee.getPhone()#">

<cfif structKeyExists(form, "save")> <cfset employee.setFirstName(form.firstname)> <cfset employee.setLastName(form.lastname)> <cfset employee.setDOB(form.dob)> <cfset employee.setEmail(form.email)> <cfset employee.setPhone(form.phone)> <cfset application.transfer.save(employee)> <cflocation url="employees.cfm" addtoken="false"> </cfif>

<h2>Edit Employee</h2>

<cfoutput> <form action="employee.cfm?id=#url.id#" method="post"> <table> <tr> <td>First Name:</td> <td><input type="text" name="firstname" value="#form.firstname#"></td> </tr> <tr> <td>Last Name:</td> <td><input type="text" name="lastname" value="#form.lastname#"></td> </tr> <tr> <td>Date of Birth:</td> <cfif isDate(form.dob)> <cfset v = dateFormat(form.dob)> <cfelse> <cfset v = ""> </cfif> <td><input type="text" name="dob" value="#v#"></td> </tr> <tr> <td>Email:</td> <td><input type="text" name="email" value="#form.email#"></td> </tr> <tr> <td>Phone:</td> <td><input type="text" name="phone" value="#form.phone#"></td> </tr> <tr> <td> </td> <td><input type="submit" name="save" value="Save"></td> </tr> </table> </form> </cfoutput>

When I'm not using a MVC based framework, I typically create self-posting forms like you see here. Starting at the top, we check to see if we are editing a new record or an existing one. Notice one calls new() and one calls get(). After I have the object I param my form fields based on all the properties of the Employee. Notice that I just check for a form submission, but don't bother validating. Thats a whole other topic and not really Transfer specific. The important line is here:

<cfset application.transfer.save(employee)>

I know I mentioned this yesterday, but it's rather cool that I don't have to worry about my object being new or old. I just save. Let Transfer worry about it. The rest of the template is a simple form and not terribly interesting.

All in all, Transfer looks pretty simple so far, wouldn't you agree? I like how I can easily get a query back without having to write the SQL myself and I certainly like the ease of use of the CRUD methods we discussed more in the previous entry. I never have to write one CFC - no beans or gateways.

Does this mean a Transfer user would never write CFCs? Of course not. I mentioned in the first entry in this series that I was intentionally avoiding Model-Glue for this application so I could keep it as simple as possible. Normally I would have a CFC in my component for Employees, but where I'd have a set of queries I'd simply use Transfer instead. In my last big Model-Glue application, I created a service CFC, a gateway CFC, a DAO CFC, and bean CFC for each type of data in the application. When I updated CFLib to use Model-Glue and Transfer, I pretty much ended up with a service CFC in model and that was it. Transfer took care of everything else! One thing that comes to mind about both Model-Glue and Transfer is - I really appreciate how one makes my life simpler by helping me lay out and organize my application structure and another makes my life simpler by abstracting away some of the more generic SQL and CFC operations I typically have to make. Together - both take care of routine things and let me focus more on the application at a high level.

Alright so where next? It would be nice if all web applications had only one type of data to deal with, but unfortunately that's not the case in the real world. Our Employee Directory won't just be a simple list of names, but a complex set of employees with relations to each other. In the next entry we will start with a new type of data, the department. I will then show how I can tell Transfer that each employee belongs to a department, and how we can make it easy to display an employee's department.

Download attached file.