Since I spent quite a bit of time wrestling with this over the last week, I figured this blog post may help others. First off, a caveat: I'm running the latest version of ColdBox 3.0.0 from SVN which is "almost" Beta 4 and the details of error handling have changed a little over the last few Betas (for the better).
ColdBox provides a number of ways to handle different types of errors. I'll cover the following options:
This is a method on your event handler CFC that is executed if the requested event identifies your handler but does not match a declared public method. This is helpful when you want to respond dynamically to certain requests, e.g., /page/about-us where Page.cfc will look up the action in a database to display certain "static" content - a mini-CMS, in other words. You could of course use /page/display/content/about-us and have a regular event handler that looks up the content but that's an uglier URL with essentially the same handler method.
You can't (shouldn't) use this to try to catch invalid event requests - you'd need it in every handler and it still wouldn't catch request like /bogus/stuff where no handler Bogus.cfc is present. That's what onInvalidEvent is for.
This is a Setting in your ColdBox XML file that identifies an event handler, e.g., "Sorry.pageNotFound", that should be executed if a request is made either for an action that doesn't exist on a handler (and which doesn't have an onMissingAction() method) or for a handler that doesn't exist.
A couple of things to be aware of:
- When your invalid event handler is executed, the view for the original (invalid) event has already been set. This means you probably need to explicitly set the view you want - event.setView( 'page/notfound' ) - because if the event requested was invalid, there's probably no such view.
- The invalid event name is passed into your handler in the private request context so you need to supply an additional argument to getCollection() or getValue(): var prc = event.getCollection( private = true ); or event.getValue( name = 'invalidEvent', private = true ). In Beta 3, the 'invalidEvent' key was stored in the (public) request context (although it wasn't always there).
This is a Setting in your ColdBox XML file that identifies an event handler, e.g., "Sorry.onException", that should be executed if an exception occurs (see also onException below). This lets you handle any exceptions in a nice clean way for your users, such as redirecting to your favorite "fail whale" page (e.g., "Sorry.somethingWentWrong"). The exception that triggered your event handler is wrapped in a coldbox.system.beans.ExceptionBean
object and placed in the (public) request context as "ExceptionBean".
If you don't redirect, the framework takes control after your handler finishes and performs standard exception handling, including displaying the default exception "Oops!" page.
This is a standard ColdBox interception point. To use this approach, write a simple interceptor that implements this method and declare it in your ColdBox XML file. The method is invoked before
any event handler declared as an "ExceptionHandler". This allows you to decouple customized logging of exceptions or whatever you want to do on the back end from whatever you want to do on the front end. The method is passed the event object (request context) and a struct containing the exception that triggered the interception point. If you return true from this method, no further interceptors are executed for this interception point (per standard ColdBox interceptor behavior).
Note that standard ColdBox logging is used to report the exception after the interception (which means you can also generate automatic email reports of exceptions without needing to intercept onException, by enabling the BugTracerReports in your ColdBox XML file or adding an EmailAppender to your LogBox settings). That means that if you attempt to redirect from onException() to a friendly event handler to display a nice message, thinking you can omit the ExceptionHandler Setting described above, your exception will not
pass through the standard ColdBox logging mechanism!
This is a Setting in your ColdBox XML file that identifies an event handler, e.g., "Sorry.noSuchPage", that should be executed if a request is made for a non-existent CFML page - and your web server / app server is setup to pass such requests to the onMissingTemplate() method in Application.cfc (it's actually declared in ColdBox.cfc which Application.cfc extends). This places the requested page path in the (public) request context as 'missingTemplate' and then treats the request as if your configured event handler had been explicitly requested instead of the non-existent page.
Other Error Handling Considerations
There is a Setting called "CustomErrorTemplate" which can specify a CFML file that ColdBox should use to format an exception report - for display to the user or to send in an email (if you enable BugTracerReports or add an EmailAppender to your LogBox settings). By default, ColdBox uses /coldbox/system/includes/BugReport.cfm
. You can override this in BugTracerReports using the CustomEmailBugReport tag.
If you don't want to handle invalid events separate from exceptions, then you'll be interested in the following exceptions:
- HandlerService.EventHandlerNotRegisteredException - this is thrown when a request comes in for which no handler can be found.
- HandlerService.invalidEventException - this is thrown when a request comes in and the handler has no matching action method (and doesn't have onMissingAction() either).
You may also be interested in Renderer.ViewNotFoundException which is thrown when a view cannot be located for a request (but the event handler was found and processed).
ColdBox's error handling capabilities are very flexible and, as with many things in ColdBox, there are several ways to tackle any given problem. This blog post is intended to cover common approaches that can be used in isolation or together to handle different types of errors. It's not intended to be comprehensive - there's always the ColdBox documentation for that!