Showing posts with label frameworks. Show all posts
Showing posts with label frameworks. Show all posts

Saturday, February 20, 2010

Another ColdFusion Framework?

Over the past couple weeks, I've spent some free time creating a simple MVC Front Controller framework for ColdFusion 9. What? Another framework for ColdFusion? Why would you want to do such a thing? While there are plenty of solid frameworks out there to choose from, none of them really showcase the power and elegance of ColdFusion 9 (and specifically ORM). Besides, it was fun to write.

While the framework is loosely based on Grails and Ruby on Rails, I've borrowed inspiration and concepts from other ColdFusion (ColdBox, ColdFusion on Wheels, Framework One, Mach-II, Model-Glue, QuickSilver) and non-ColdFusion (Spring, jQuery, Swiz) frameworks, as well as incorporated some of my own tips and tricks, too. Best of all, it's powered by ColdFusion 9, Hibernate, and ColdSpring.

Without going into too many specifics, here are some key concepts in the framework:
* convention over configuration
* MVC design pattern
* automatic creation of controller beans
* implicit invocation of controller actions
* centralized event dispatching
* metadata-driven AOP
* dynamic finders
* global helpers available using $
* implicit rendering of views and layouts
* helper tags and method plugins for views
* form data binding
* params and flash scopes

Finally, here's a sample application I created called UserDirectory, which performs your basic user CRUD.



Application.cfc

/**
* @extends coldmvc.Application
*/
component {

}


config/settings.ini

[default]
controller=users

[development]
development=true


app/controllers/UserController.cfc

/**
* @action list
* @extends coldmvc.Controller
*/
component {

function list() {

var paging = $.paging.options();

var options = {
sort = "firstName",
order = "asc",
max = paging.max,
offset = paging.offset
};

var search = $.params.get("search");

if (search != "") {
params.users = _User.findAllByFirstNameLikeOrLastNameLike(search, search, options);
params.count = _User.countByFirstNameLikeOrLastNameLike(search, search);
}
else {
params.users = _User.list(options);
params.count = _User.count();
}

}

function edit() {

var userID = $.params.get("userID");
params.user = _User.get(userID);

}

function save() {

var user = _User.get(params.user.id);
user.populate(params.user);
user.save();

flash.message = "User saved successfully";
redirect("edit", "userID=#user.id()#");

}

function delete() {

var user = _User.get(params.userID);
user.delete();

flash.message = "User deleted successfully";
redirect("list");

}

}


app/model/User.cfc

/**
* @extends coldmvc.Model
* @persistent true
*/
component {

property id;
property firstName;
property lastName;
property email;

}


app/views/users/list.cfm

<cfoutput>
<form>
Search: <input name="search" value="#search#" wrapper="false" />
</form>

<table label="Users">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<each in="#users#" value="user" index="i">
<tr index="#i#">
<td>#user.firstName()#</td>
<td>#user.lastName()#</td>
<td>#user.email()#</td>
<td><a href="#linkTo('edit','userID=#user.id()#')#">Edit</a></td>
<td><a href="#linkTo('delete','userID=#user.id()#')#">Delete</a></td>
</tr>
</each>
<cfif users.size() eq 0>
<tr>
<td colspan="3">No users have been added yet</td>
</tr>
</cfif>
</table>
<paging records="#count#" />
<a href="#linkTo('edit')#">Add a User</a>
</cfoutput>


app/views/users/edit.cfm

<cfoutput>
<fieldset label="User Information">
<form action="save" bind="user">
<hidden name="id" />
<input name="firstName" />
<input name="lastName" />
<input name="email" />
<submit />
<cfif user.exists()>
<a href="#linkTo('delete','userID=#user.id()#')#">Delete</a>
</cfif>
<a href="#linkTo('list')#">Back to List</a>
</form>
</fieldset>
</cfoutput>


app/layouts/users.cfm

<cfoutput>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en-us" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>User Directory</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
#renderCSS("reset.css")#
#renderCSS("style.css")#
#renderJS("jquery.1.4.2.js")#
</head>
<body>
<cfif structKeyExists(params, "message")>
<div class="flash">
#params.message#
</div>
</cfif>
<div class="content">
#render()#
</div>
</body>
</html>
</cfoutput>


If you couldn't tell from the code, I've named the framework ColdMVC. Pretty boring, right? If someone has a better idea, I'm open for suggestions. I've written a handful of small sample applications with the framework already and, to be honest, it's made programming fun again. Plus, writing everything in cfscript syntax makes ColdFusion finally feel like a real scripting language.

Eventually I'd like to release the framework as open source, but I haven't had the time to make it happen yet. Plus there are a couple more features I'd like to finalize first, like validation and more robust route mapping. In the meantime, if anyone is interested in learning more or seeing some more code, shoot me an email or feel free to track me down at cf.Objective() in a couple weeks.

Wednesday, December 9, 2009

7 reasons I switched back to ColdFusion...

First, read this article: 7 reasons I switched back to PHP after 2 years on Rails.

Now, read it again, only this time replace the word "PHP" with "ColdFusion".

Languages are like frameworks: it doesn't really matter which one you use, they all pretty much do the same thing. There is no Holy Grail. In the end, it's all just a bunch of 0's and 1's that can help you get things done.

Monday, September 21, 2009

ColdFusion and Frameworks

If you haven't read it yet, I would suggest reading this post by Matt Woodward. Very good points.

Honestly, if ColdFusion has been around for almost 15 years, why don't we have anything that comes even remotely close to Ruby on Rails or Grails? You could make the case that ColdFusion on Wheels and ColdBox are similar in their implementations, but then there are people that swear by Model-Glue, Mach-II, and Fusebox... and then there's Edmund, FW/1, onTap, etc... and those are just the front controller frameworks. If you want the total package, you'll have to wire in ColdSpring, LightWire, Transfer, Reactor, MXUnit, cfcUnit, cfSpec, etc...

Unfortunately, the ColdFusion framework community is so fragmented that I don't think there will ever be a widely-accepted, well-designed, dominant framework - a framework that just works - a framework that some developers might actually confuse with a language, like what happens with Rails(Ruby) and Grails(Groovy). Right now there are just too many smart ColdFusion developers all working on their own versions of the same thing.

Friday, August 28, 2009

CF9 Front Controller Framework

I want to start writing a very simple front controller framework for CF9 that combines convention simplicity from ColdBox with configuration flexibility from Model-Glue, while borrowing a couple things from Rails/Grails/SpringMVC. Here's what a sample controller might look like:


component extends="Controller" {

public void function listUsers() {

var users = list("User");

render("users/list.cfm",{users=users});

}

public void function showUser() {

var user = get("User",params.userID);

render("users/show.cfm",{user=user});

}

public void function editUser() {

if(exists(flash,"user")) {
var user = flash.user;
}
else {
var user = get("User",params.userID);
}

render("users/edit.cfm",{user=user});

}

public void function saveUser() {

var user = get("User",params.userID);

populate(user,params);

var errors = validate(user);

if(!has(errors)) {

save(user);

flash.message = "User updated successfully";

redirect("showUser",{userID=user.getID()});

}
else {

flash.user = user;

flash.message = errors;

redirect("editUser",{userID=user.getID()});
}

}

public void function deleteUser() {

delete("User",params.userID);

flash.message = "User deleted successfully";

redirect("listUsers");

}

}