Entries Tagged as Metro

Metro 0.9 Now Available

Metro is creeping ever closer to a 1.0 release, which will likely be followed up by something else in short order.

Metro 0.8.2 Now Available

The latest release for Metro (0.8.2) is now available. This release sees the addition of another service method and some significant updates to the service api.

create
The new create returns a populated and validated Transfer object. If the object passes validation, it is persisted. The default validation context is "all". Here is the method.

<cffunction name="create" access="public" output="false" returntype="any" hint="I return a populated and validated Transfer object.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="input" type="struct" required="true" hint="The input struct of key/value pairs.">
<cfargument name="context" type="string" required="false" hint="The validation context." default="all">
<cfset var obj = new(objectName: arguments.objectName)>
<cfset obj.populate(args: arguments.input)>
<cfif obj.validate(context: arguments.context)>
<cfset getGateway(arguments.objectName).save(obj)>
</cfif>
<cfreturn obj>
</cffunction>

save
The save method now also returns a populated and validated Transfer object. If the object passes validation, it is persisted. The default validation context for save() is "all". The difference between create and save is that the former populates and validates a new object, whereas the latter "gets" the object using the input struct as the key (get will intelligently build the correct key from the input struct) and uses clone(). Here is the method.

<cffunction name="save" access="public" output="false" returntype="any" hint="I return a populated and validated Transfer object.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="input" type="struct" required="true" hint="The input struct of key/value pairs.">
<cfargument name="context" type="string" required="false" hint="The validation context." default="all">
<cfset var obj = get(objectName: arguments.objectName, key: arguments.input).clone()>
<cfset obj.populate(args: arguments.input)>
<cfif obj.validate(context: arguments.context)>
<cfset getGateway(arguments.objectName).save(obj)>
</cfif>
<cfreturn obj>
</cffunction>

You can probably guess that I use create when trying to persist a new object and save for an update. Let's look at a sample coldbox controller that uses create or save.

<cffunction name="doSave" access="public" returntype="void" output="false">
<cfargument name="Event" type="any">

<cfscript>
var obj = "";
var context = "";
var message = "";
if (event.getValue("UserId",0) == 0) {
// create
context = "new";
message = "User successfully Added.";
obj = getUserService().create(objectName: "User", input: event.getCollection());
} else {
// save
context = "edit";
message = "User successfully Edited.";
obj = getUserService().save(objectName: "User", input: event.getCollection());
}
if (!obj.hasErrors()) {
setMessage(type: "success", message: message);
setNextEvent("user.list");
} else {
event.setValue("User",obj);
setNextEvent(event: "user." & context, persist: "User");
}
</cfscript>
</cffunction>

In the past, the save() method returned a result with a success flag, an array of errors and the obj as a payload that you could access via getResult(). I have since moved to maintaining the errors within the Transfer object, which renders a result object useless. Thus the change to the save() method.

list
The list method now accepts the "orderBy" and "asc" arguments to provide better control of simple list operations. Here is the list() mthod.

<cffunction name="list" access="public" output="false" returntype="query" hint="I return a query by object name and filter.">
<cfargument name="objectName" type="string" required="true" hint="The Transfer object name.">
<cfargument name="filter" type="struct" required="false" default="#StructNew()#" hint="The input filter of key/vlaue pairs.">
<cfargument name="orderBy" type="string" required="false" default="" hint="The optional property name to order by.">
<cfargument name="asc" type="boolean" required="false" default="true" hint="The boolean flag to specify whether to sort ascending or descending.">
<cfreturn getGateway(arguments.objectName).list(filter:arguments.filter, orderBy:arguments.orderBy, asc:arguments.asc)>
</cffunction>

If the filter param contains properties found in the object class, the gateway will use transfer's listByPropertyMap(), instead of list().

Finally, the create(), save() and delete() methods have the Transfer transaction advice applied to them. This allows one to write more complex methods that are transaction safe.

Metro 0.7 Released

The latest Metro release (0.7) provides new behaviour to the core Service and Gateway and to the user package domain objects as well as some bug fixes, minor updates and code cleanup.

Metro 0.6 Released

When developing OSS software, one should endeavour to maintain backward compatibility with each new release while adding improvements and new features (and fixing bugs). The current Metro release (0.6) is a significant departure from previous releases. While it maintains backward compatibility for service and gateway methods, it also provides improved support for validation rules and contexts thanks to a huge contribution from Matt Quackenbush. The changes are designed to promote building rich business objects. I removed some of the setup dependencies which I was unhappy with, and now use "import" for ColdSpring and "include" for Transfer to simplify configuration. Lastly, I have also re-organized sample code and support documents. Here is breakdown of the items requiring modification to use Metro 0.6.

Metro 0.5 Released

I'm pleased to announce the release of Metro 0.5. The biggest change for this release is compositeid support contributed by Bob Silverberg, cf.Objective() speaker and master of Transfer metadata. You'll find sample code in the new work package that models an Employee, EmployeeType and Department.