Published on ColdFusion Zone (http://coldfusion.dzone.com)
ModelGlue Layout Factory
By dan
Created 2008/02/28 - 9:31pm

Many developers want to add AJAX enhancements to an application. When that application uses a front controller, the inevitable question comes, should the remote request also route through the front controller?

The answer is, as always, It Depends!

If the remote requests will primarily pull data back from the back end, then this is a good indicator the requests should pipe through a Remote Service Layer. On the other hand, when the nature of the AJAX requests simply need to make partial page updates, I push them through my front controller.

Why? Clearly generating HTML is much easier and cleaner inside of the front controller. My favorite front controller framework, Model-Glue, has all sorts of helpful functionality like a dependancy injection, business logic, an event manager and a view manager all in one place.

Now that we have a general rule, (data=remote service, partial page generation=front controller), we can look at a practical example.

Suppose I have an event written in my ModelGlue.xml configuration called getUserList. This event contains all the logic necessary to process security, pull the user list from the persistance layer, generate an HTML fragment for the user list and include the HTML Header and Footer for our layout. This event handler looks like this:

<event-handler name="User.List">
<broadcasts>
<message name="needAuthentication" />
<message name="needUserList" />
</broadcasts>
<views>
<include name="content" template="userlist.cfm" />
</views>
<results>
<result do="MainLayout" />
</results>
</event-handler>

<event-handler name="MainLayout">
<views>
<include name="header" template="header.cfm" />
<include name="footer" template="footer.cfm" />
</views>
</event-handler>

When User.List is called, two event handlers actually run. The second event, MainLayout is called via a result. Using this technique is very nice. Now suppose we get a requirement to allow the user list to be called from AJAX? Since we already have a header and footer, and a User list for that matter, all we want to to is replace the User list on the page with the new User list. Certainly we need a new event, since we don't want to add in the header and foorter with this new request. Let's refactor:

<event-handler name="User.List">
<broadcasts>
<message name="needAuthentication" />
<message name="needUserList" />
</broadcasts>
<views>
<include name="content" template="userlist.cfm" />
</views>
<results>
<result do="Layout.Factory" />
</results>
</event-handler>

<event-handler name="MainLayout">
<views>
<include name="header" template="header.cfm" />
<include name="footer" template="footer.cfm" />
</views>
</event-handler>

<event-handler name="Layout.Factory">
<broadcasts>
<message name="needLayoutType" />
</broadcasts>
<results>
<result name="print" do="PrintLayout" />
<result name="ajax" do="AJAXLayout" />
<result name="html" do="MainLayout">
</results>
</event-handler>

Now, if you follow the code, 3 events will run when the initial User.List is requested. User.List, then Layout.Factory then presumably the MainLayout. Since the Model-Glue framework allows named results to be queued, we can put a tiny bit of logic inside the needLayoutType message handler to queue the correct result for the particular request. Our needLayoutType broadcast will delegate to this function, primarily tasked with pulling out the Format parameter from the event object, verifying it from a list of approved layouts, and then adding the correct result to the event. See here:

<cffunction name="doLayoutResult" output="false" access="public" returntype="void">
<cfargument name="Event" type="any" required="true"/>

<cfset var requestedLayout = arguments.event.getValue("Format") />
<cfset var DefaultLayout = arguments.event.getValue("CFG.DefaultLayout") />

<cfif len( trim( requestedLayout ) ) AND getModelGlue().getBean("Config").isAllowedLayout( requestedLayout )>
<cfset arguments.event.addResult( requestedLayout ) />
<cfelseif len( trim( DefaultLayout ) ) >
<cfset arguments.event.addResult( DefaultLayout ) />
</cfif>

</cffunction>

Now, depending on the request parameters, I can tailor the output to match the need, without having to create whole new paths in our Model-Glue application, I've only created some additional XML configuration in my ModelGlue.xml file.

Using this model, we could support any type of special layout or format. You could output to an Image (using the sweet image functions in ColdFusion), a Powerpoint document, a PDF, the possibilities are endless.

 

 

 

 

 

 


Source URL: http://coldfusion.dzone.com/blogs/dan/2008/02/28/modelglue-layout-factory