Saturday, April 24, 2010

GORM vs ColdMVC ORM

One of the more interesting session's at cf.Objective() was Matt Woodward's presentation CFML on Grails. In the presentation, Matt showed how he was able to create a CFML plugin for Grails in order to integrate ColdFusion and Grails.

While the code worked, it seemed a little sketchy at times trying to get the two languages to play nice together cohesively. Even so, Matt achieved his goal of integrating the languages, so he gets props for that.

In his presentation, Matt said one of the biggest advantages of using Grails is being able to leverage Grails Object Relational Mapping (GORM), which is essentially a user-friendly abstraction layer on top of Hibernate.

While Matt took the approach of integrating ColdFusion into Grails in order to use GORM, I took the opposite approach by trying to recreate GORM in ColdFusion inside my ColdMVC framework. Not everything from GORM has been ported over yet, but here's a set of examples for comparison's sake. The top line in each pair is Grails, while the second line is ColdMVC.


def count = Book.count()
var count = _Book.count();

def count = Book.countByTitle("The Shining")
var count = _Book.countByTitle("The Shining");

def count = Book.countByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
var count = _Book.countByTitleAndAuthor("The Sum of All Fears", "Tom Clancy");

def book = Book.find("from Book as b where b.author=:author",[author:'Dan Brown'])
var book = _Book.find("from Book as b where b.author=:author",{author='Dan Brown'});

def book = Book.findAll("from Book as b where b.author=? order by b.releaseDate",['Dan Brown'],[max:10, offset:5])
var book = _Book.findAll("from Book as b where b.author=? order by b.releaseDate",['Dan Brown'],{max=10, offset=5});

def book = Book.findByTitle("The Shining")
var book = _Book.findByTitle("The Shining");

def books = Book.findAllByTitleLike("%Hobbit%")
var books = _Book.findAllByTitleLike("Hobbit");

def books = Book.findAllByTitle("The Shining", [max:10, sort:"title", order:"desc", offset:100])
var books = _Book.findAllByTitle("The Shining", {max=10, sort="title", order="desc", offset=100});

def book = Book.findWhere(title:"The Shining", author:"Stephen King")
var book = _Book.findWhere({title="The Shining", author="Stephen King"});

def books = Book.findAllWhere(author:"Stephen King")
var books = _Book.findAllWhere({author="Stephen King"});

def book = Book.get(1)
var book = _Book.get(1);

def books = Book.getAll(2,1,3)
var books = _Book.getAll(2,1,3);

def books = Book.getAll([1,2,3])
var books = _Book.getAll([1,2,3]);

def books = Book.list()
var books = _Book.list();

def books = Book.list(max:10, offset:100, sort:"title", order:"desc")
var books = _Book.list({max=10, offset=100, sort="title", order="desc"});


As you can see, aside from a couple small syntax differences, they're almost identical.

Wednesday, April 21, 2010

ColdMVC: Event Listeners

ColdMVC provides your application with several interception points throughout the lifecyle of a request. This is possible thanks to centralized event dispatching from ColdMVC’s EventDispatcher component. In a typical ColdMVC request, the following events will be dispatched:

• requestStart
• actionStart
• preAction
• pre:{controller}Controller
• pre:{controller}Controller.{action}
• action
• post:{controller}Controller:{action}
• post:{controller}Controller
• postAction
• actionEnd
• requestEnd

Any controller within the application can listen for these events by applying metadata to the desired listener method. The events metadata is a comma-separated list of regular expressions, providing quite a bit of flexibility in intercepting. As an example, if you wanted a SecurityController to verify a user is logged in at the beginning of each request, you could have the following code:

component {

/**
* @events requestStart
*/
function verifyLoggedIn() {
if (!session.isLoggedIn) {
redirect({controller="security", action="logout"});
}
}

}

Furthermore, ColdMVC will implicitly invoke certain methods on your request’s controller if they are defined. Before the request’s action is invoked, ColdMVC will invoke the controller’s pre and pre{Action} methods if they exist. Next, ColdMVC will invoke the action for the request, followed by the post{Action} and post methods if they exist. For example, if the current requst is /product/list, ColdMVC will invoke ProductController.pre(), ProductController.preList(), ProductController.list(), ProductController.postList(), and finally ProductController.post().

Tuesday, April 20, 2010

ColdMVC: Plugins

Plugins are custom functions that are available to your views and layouts that help keep your presentation layer clean. Plugins are defined using a simple .cfm file that maps a plugin name to a method on either a helper or a bean defined within ColdSpring.

When you first create an application using ColdMVC, you'll already have access to a standard set of plugins, defined inside /coldmvc/config/plugins.cfm. The most prominent plugin is the linkTo() method that builds URLs for your views.

When ColdMVC loads, it will load any plugins that are found inside your application's /app/config/plugins.cfm, then any plugins inside /coldmvc/config/plugins.cfm. If you would like to override one of ColdMVC's plugins, simply define your own plugin with the same name as the ColdMVC plugin.

While your views and layouts still have access to all of your application's helpers, it is recommended to use plugins rather than the helpers. Even though they will generate the exact same HTML, #linkTo({controller="post", action="list"})# reads a lot better than #$.link.to({controller="post", action="list"})#.

ColdMVC: Custom Tags

Writing views and layouts can be tedious work, especially if you want to ensure you’re using consistent HTML markup around your form fields. To make views a little less painful, it’s best to use custom tags to generate the HTML for you. That way, you don’t have to worry small things like radio button markup and instead can focus on more important things, like your application’s business logic.

A new installation of ColdMVC will already have a standard library of custom tags available to use inside your views, such as <c:input />, <c:select />, and <c:textarea />. These files are all located within /coldmvc/tags.

You can create your own custom tags in a ColdMVC application simply by placing a .cfm file inside your application’s /app/tags folder. For example, if you created a file located at /app/tags/tony.cfm, you would then have access to that custom tag inside your views and layouts by using <c:tony />.

When ColdMVC first loads, it will load any custom tags located within your application’s /app/tags folder, then any custom tags inside /coldmvc/tags folder that haven’t been loaded yet. These custom tags will then be available to all of your views and layouts.

Most of the default custom tags inside ColdMVC simply delegate their functionality to a ColdMVC helper component, so extending the default custom tags can be done by extending the helpers. If you would like to completely override a custom tag that ships with ColdMVC, simply create a custom tag with the same file name inside your application’s /app/tags folder, and ColdMVC will load your custom tag rather than ColdMVC’s custom tag.

By default, ColdMVC will import the custom tags using a “c” prefix. If you would like to change the prefix to something else, such as “foo”, you can do so inside your /config/config.ini file by setting tagPrefix=foo. However, it is recommended as a best practice to use the default tag prefix of “c” to provide framework consistency across projects.

In a typical ColdFusion application, you need to import your custom tags into each ColdFusion template using the <cfimport /> tag. However, you do not have to do this inside a ColdMVC application. For each view and layout in your application, ColdMVC will automatically generate a corresponding .cfm file inside your application’s /.generated folder that contains the content of your template along with the <cfimport /> tag.

Most of the templates are generated the first time they are requested, with the exception of files beginning with an underscore, which are considered “private” templates by convention and therefore are generated when the application first loads.

Monday, April 19, 2010

ColdMVC: Helpers

ColdMVC allows you to create helper components that are globally available to your entire application. These helper components are good for containing useful functions similar to those found on cflib.org.

When ColdMVC first loads, it will load any helpers located within your application’s /app/helpers folder, then any helpers inside ColdMVC’s /helpers folder that haven’t been loaded yet. These helpers will then be globally available throughout your application inside the $ variable.

ColdMVC ships with a handful of helpers that can be found inside /coldmvc/helpers. If you would like to override the functionality of one ColdMVC’s helpers, simply create a .cfc with the same name inside your application’s /app/helpers directory, extend the corresponding ColdMVC helper, and make your changes.

You can create your own helpers by creating a .cfc and placing it inside your application’s /app/helpers folder. The newly created helper is then available throughout your application inside the $ variable. For example, if you created a file located at /app/helpers/tony.cfc, you would then have access to that helper throughout your application by using $.tony.