This is the second half of our two-part conversion of a FuseBox 5.1 sample app to ColdBox MVC.  If you haven't been following our blog series on converting your legacy FuseBox apps over to ColdBox MVC you may want to back up and read the previous post first..  In that post we took a look at the different files in each version of the app.  We talked about how each framework bootstraps itself up, as well as settings and circuits/handlers.  We'll pick up right were we left off in this post and finish off the code by looking at how we converted the views, models, and error handling.

Views

ColdBox will automatically look for a view file named after your action in a folder named after your handler.  Of course, all this happens in our "/views" convention folder.  You are free to name your view files whatever you want though.  Just use the following code to tell the framework what view to include:

// Include /views/randomFolder/randomFile.cfm
event.setView( "randomFolder/randomFile" );

Our views are almost identical.  There are two main differences.  The first is that our views "get" data from the handler by accessing the readily-available rc (request collection) and prc (private request collection) scopes.  rc is used for any input from the user via FORM or URL scopes.  prc is for any other data the handler wants to pass along to the view.  The second is in how we build links.

/view/listEmails.cfm

<a href="#self##xfa.conform#">Return to Connect Form</a>

/views/list.cfm

<a href="#event.buildLink( prc.xeh.conform )#">Return to Connect Form</a>

ColdBox gives you a nice helper method in the event object to build links for you.  It automatically handles HTTPS, the base domain, app mapping, and query string.  event.buildLink() can also generate SES URLs with no changes when you have it enabled.

Layouts

ColdBox layouts are placed in a folder called /layouts by default and unless you've specified something else, will look for a file called Main.cfm.

/layouts/Main.cfm

<cfoutput>
	<html>
		<head>
			<link href="/includes/getmymail.css" rel="stylesheet" type="text/css" />
		</head>
		<body>
			#renderView()#
		</body>
	</html>	
</cfoutput>

The renderView() call is where the output from the view will be placed.

Model

Your models are your services, beans, and DAO that represent the business logic in your application.  In ColdBox, these go under a folder called /model.  I created a MailService.cfc which encapsulates getting a list of messages and getting a single message.  

/model/MailService.cfc

component singleton {
	property name="attachmentPath" inject="coldbox:setting:attachmentPath";
	property name='sessionStorage' inject='coldbox:plugin:sessionStorage';
	
	function getAllMessages( required numeric start	) {
		// Get connection Info
		var connectionInfo = sessionStorage.getVar( 'connectionInfo' );
		
		return new pop().getHeaderOnly(
			server = connectionInfo.serverName,
			username = connectionInfo.userName,
			password = connectionInfo.password,
			port = connectionInfo.serverPort,
			maxrows = connectionInfo.msgsPerPage,
			startrow = arguments.start
		);
	}
	
	function getMessage( required string uid ) {
		// Get connection Info
		var connectionInfo = sessionStorage.getVar( 'connectionInfo' );
				
		return new pop().getAll(
			server = connectionInfo.serverName,
			username = connectionInfo.userName,
			password = connectionInfo.password,
			port = connectionInfo.serverPort,
			uid = arguments.uid,
			attachmentpath = attachmentPath,
			generateuniquefilenames = true
		);
	}	
}

Note the singleton annotation at the top in the component definition.  This tells WireBox to only create one instance of this service that the entire application shares.  I'm also using properties to inject a reference to my attachmentPath setting as well as the sessionStorage plugin again.  No configuration is necessary for WireBox to find the MailService CFC since we've placed it in the /model convention folder.  Unfortunately, I found that Railo doesn't support the same script syntax for the CFPOP tag so I also created a RailoMailService.cfc file in the /model folder and created the following WireBox configuration file.

/config/WireBox.cfc

component extends='coldbox.system.ioc.config.Binder' {
	function configure() {		
		// Use this to detect the CFML engine
		var CFMLEngine = new coldbox.system.core.util.CFMLEngine(); 
		
		// Railo uses a different script syntax
		if( CFMLEngine.getEngine() == CFMLEngine.RAILO ) {
			// This will override the default MailService mappings
			map( 'MailService' ).to( 'model.RailoMailService' );		
		}
		
		// No "else" needed for Adobe CF. WireBox will simply "find" the 
		// "MailService" CFC in the "/model" folder automatically.		
	}
}

This file uses a utility built into ColdBox called CFMLEngine to detect the engine in use and conditionally overwrite the MailService mapping to point to the Railo version.

Error Handling

In the FuseBox code, there are try/catches around a lot of code in the "model" files.  If an error occurs, a custom error page is included.  

<cftry>
<cfpop  .../>
	<cfcatch>
		<cfinclude template="../view/error/connectionError.cfm" />
	</cfcatch>
</cftry>

What if an error occurs somewhere else in the request though?  What if you add new code and forget to wrap it in a try/catch.  Even worse, what if you decide to rename your error template after it's referenced everywhere?  In ColdBox, error handling is built in.  All of your code is run in a try/catch at the framework level, and there's a nice default error template that displays.  In your production settings though, you'll want to override this to a more secure page that doesn't divulge information with the customErrorTemplate setting.

customErrorTemplate = "includes/templates/oops_sorry.cfm"

You can read more about the exception handling provided to you in ColdBox here.

Conclusion

To see all the code, please visit this repo on GitHub: https://github.com/bdw429s/FuseBox-5.1-Sample-App-Conversion

This sample app was a little more involved than the last one, and hopefully everything makes sense even though I included a lot more code.  If clone the Git repo you can unzip the FuseBox code and open them side by side.  Please comment below if you have any questions or suggestions, and here's our list of handy resources: