ColdBox's Event Handlers Guide
- ColdBox's Event Handlers Guide
- Introduction
- What are Event Handlers?
- How are events called?
- Implicit Declared Events
- Event Handlers Location
- Event Handlers External Location
- Rules and Anatomy of an Event Handler
- Sample Handler Component Declaration
- The Caching Parameters
- Reserved Words and Methods
- Sample Init Method
- Anatomy of an Event Handler Method
- Event Caching
- Method Samples
- How to set and get values (Event Handlers, Views, Layouts)
- How to relocate to another event
- Setting Views
- What if I don't want to render anything?
- Rendering Data
- Event Default Action
- Event Handler Implicit Events: preHandler, postHandler
- onMissingAction convention
- Handler Public Property: this.EVENT_CACHE_SUFFIX
- Persisting Flash Variables
- Executing Events
- Autowiring Your Handlers
- Best Practices
- Advanced OO Features: UDF Injections
Introduction
This is a guide to event handlers for the ColdBox Coldfusion Framework. It will give you a quick overview of event handler syntax, regulations, locations, method invocations, and declarations. It will also show you some event handler code samples. Event handlers are synonymous to the word Controller in the MVC design pattern. So every time you hear event handler, you are taking about a controller.
What are Event Handlers?
ColdBox event handlers are cfc's (Coldfusion Components) that are written to implement ColdBox events that can be trigger externally via FORM/URL/REMOTE or internally by a developer. These events carry the task of controlling your application flow, calling business logic, preparing a display to a user and much more. Every method that has an access of public/remote is automatically exposed as a runnable event in the ColdBox framework and ColdBox will auto-registered for you. These events can then be defined for some explicit or implicit invocations via the coldbox.xml and from within the components themselves. Another important aspect of event-driven architectures is that the event action can be passed via the URL or the FORM, thus trigger an event in the system. The framework captures this action variable and uses it to execute the correct event handler method. From within the event handler's method, you will program the flow of the application, redirect data to the correct business logical units (model calls), logging, error trapping, validation, etc. If you have a Fusebox background you can relate to a handler cfc to being a circuit file and the methods in the handler to be like the fuseactions in the circuit file. However, with one MAJOR difference, you are coding in coldfusion and not in XML. There is no need for parsing or an XML dialect. Another major advantage is the benefit of using Coldbox Plugins from within your handlers, which provide you with several programming aspects that are already pre-built for you.
If you are not familiar with coldfusion components, you will have to get to speed in their usage in order to use the ColdBox framework. Below are some resources on Coldfusion Components:
- Intro to CFC's by Ben Forta
- Coldfusion Articles
- Coldfusion Component Tips by O'reilly
- ColdFusion Components: A powerful tool for CF developers By: Jeffry Houser
How are events called?
As discussed in the introduction, events are determined via a special variable that can be sent in via the FORM or URL or REMOTELY. The default name for this variable is event. Of course, you can change this by updating the EventName setting in your configuration file. If no event name is detected as an incoming variable, the framework will look in the configuration settings for the DefaultEvent setting and use that instead. Ok, so now that we know how we can determine what event to execute, how do we write the events since they are used by convention?
All event handlers must be placed in the conventions directory of handlers in the application root. (See Directory Structure). At application startup, the framework registers all the valid event handler cfc's. So in order to call them you will use the following dot notation format:
{handler}.{method} = ColdBox Event
{package}.{handler}.{method} = ColdBox Event
This looks very similar to a java/cfc method call, example: String.getLength(), but without the parenthesis. Once the event variable is set and detected by the framework, the framework will tokenize the event string to retrieve the cfc and method call and validate it against the internal registry of registered events. It then continues to instantiate the event handler cfc or retrieve it from cache, and then finally executes the event handler's method.
Event url syntax can be done the regular way of index.cfm?event= or by using the ColdBox advanced SES routing system: index.cfm/handler/action. To learn more about routing, I suggest reading the SES pretty url guide AFTER this guide.
Examples:
//No Packages index.cfm?event=main.index //With SES routing index.cfm/main/index
This will tell the framework too look for the main.cfc and execute the index() method.
//With Package index.cfm?event=blog.main.entry //With SES Routing index.cfm/blog.main/entry
This will tell the framework too look for the blog directory and then for the main.cfc and execute the entry() method.
So just remember that when declaring event variables, they have to follow the dot notation.
Implicit Declared Events
There are several events that can be declared implicitly in your configuration file. They are declared there because they correspond to several execution points in the life cycle of an application. Let's explore them:
- Default Event : The default event to execute if no incoming event is detected
- Request Start Handler : The event to execute at the beginning of every request
- Request End Handler : The event to execute at the end of every request.
- Session Start Handler : The event to execute at the beginning of a user's session
- Session End Handler : The event to execute at the end of a user's session
- Application Start Handler : The event to execute at the startup of the application
- onInvalidEvent : The event to execute when the incoming event is invalid
- onException : The event to execute when ANY exception is trapped within the framework.
I highly suggest also looking at the ColdBox Application Life Cycle Guide. To understand how they are fired. Also, please look at the application template's main.cfc handler. As it contains the skeleton of all of these events, as some of them have special variables in them.
Event Handlers Location
All event handlers should be placed in the handlers directory of your application. This is the location where ColdBox will look for event handlers, parse them and register them. However, you can also change this convention via the Dashboard or settings.xml file or configure the per-application conventions in your configuration file. All of the framework's conventions can be customized to your liking. Please see Naming Conventions Guide
|ApplicationRoot |----+ handlers (Event Handlers Directory
Event Handlers External Location
You can also declare a HandlersExternalLocation setting in your configuration file. This will be a dot notation path or instantiation path where more external event handlers can be found (You can use coldfusion mappings). Once declared, the framework will search that location for event handler cfc's and register them as external events. How will I call them then? The same way as normal events, using the syntax shown above. There is no distinction on your part, only for the framework. How cool is that?
Rules and Anatomy of an Event Handler
- First of all, these cfc's must extend the coldbox eventhandler base cfc: coldbox.system.eventhandler
- They must have an init method with the following standard IF and only IF you will be putting any initialization code for the entire event handler. If not, the init method is not mandatory.
- They must exist in the correct handlers directory under your application. See Directory Structure or wherever you have pointed your custom conventions.
- They must NOT contain any business logic, that is what the model or business layer is for, unless you don't want to.
- They must determine what view will be rendered or what event to redirect execution to via a redirect or just implicitly giving execution to another event.
- If the handlers are called via the ColdBox proxy from Flex/Air/Remote applications, your event handlers can actually return data by having a return type and returning a value.
- They must have the public/remote exposed methods that will respond as external ColdBox events.
- Private events have an access type of private and can only be called from within the application by using the runEvent() method.
- Handlers are cached by default, unless the handler caching setting is off. You can configure persistence via metadata.
- You can easily wire up dependencies in your handler from coldspring/lightwire or the coldbox cache by using the autowire interceptor.

Sample Handler Component Declaration
Below is a sample handler component declaration which can exhibit some caching parameters discussed below:
<cfcomponent name="security" hint="This is my security handler" extends="coldbox.system.eventhandler" cache="true" cachetimeout="20" cacheLastAccessTimeout="5"> <!--- All my methods here ---> </cfcomponent>
The Caching Parameters
Since ColdBox is built with a solid cache foundation, your handlers can also be cached if needed. You will do this by adding meta data attributes to the cfcomponent tag. By default handlers WILL BE cached, unless you specifically use the cache meta data attributes to tell the framework NOT to cache it. Caching of handlers simulates persistence, so remember this if you are planning handlers that can maintain their own persistence and ALWAYS ALWAYS var scope your function variables. That is the number one reason for illusive errors and bad best practices.
| ATTRIBUTE | TYPE | DESCRIPTION |
| cache | boolean | A true or false will let the framework know whether to cache this handler object or not. |
| cachetimeout | numeric | The timeout of the object in minutes. This is an optional attribute and if it is not used, the framework defaults to the default object timeout in the cache settings. You can place a 0 (Zero) in order to tell the framework to cache the handler for the entire application timeout controlled by coldfusion. |
| cacheLastAccesstimeout | numeric | The last access timeout of the object in minutes. This is an optional attribute and if it is not used, the framework defaults to the default last access object timeout in the cache settings. This tells the framework that if the object has not been accessed in X amount of minutes, then purge it. |
Reserved Words and Methods
For a full list of reserved words and methods for handlers, please visit our Reserved Guide. I really recommend you read about this methods because that is how you interact with the framework. Some common methods are shown below:
- announceInterception() : Announce a ColdBox interception
- getColdboxOCM() : get a reference to the cache manager
- getController() : get a reference to the coldbox controller
- getDebugMode() : Whether you are in debug mode or not.
- getfwLocale() : get the locale
- getInterceptor() : Get an interceptor reference (only if loaded)
- getMyPlugin() : Get a custom plugin
- getPlugin() : Get a core or custom plugin
- getResource() : Get a resource string from a resource bundle
- getSetting() : Get a setting from your configuration file.
- htmlhead() : Send text to the html head.
- include() : Facade for cfinclude
- dump() : facade for cfdump
- abort() : facade for abort
- includeUDF() : Inject a UDF into your handler
- persistVariables() : Persist variables in the framework's flash ram
- renderView() : Render View
- runEvent() : Run an event
- setNextEvent() : Relocate to the next event
- setNextRoute() : Relocate to another route (SES)
- setSetting() : set a new setting
- settingExists() : Check if a setting exists
- throw() : facade to cfthrow
Sample Init Method
The following is a sample init method that basically calls the super.init() method to initialize the handler and then continues to set some local properties for the handler. Remember that handlers ARE objects and have their own identity and persistence. As a best practice, ALWAYS create the init() method.
//Empty Init Method <cffunction name="init" access="public" returntype="ehGeneral" output="false"> <cfargument name="controller" type="any" required="yes"> <cfscript> //Calling the the super init method is MANDATORY super.init(arguments.controller); //return instance return this; </cfscript> </cffunction> //Custom Init Method <cffunction name="init" access="public" returntype="ehGeneral" output="false"> <cfargument name="controller" type="any" required="yes"> <cfscript> //Calling the the super init method is MANDATORY super.init(arguments.controller); //Any Code you like below setCreated(true); setWhatever( getPlugin('ioc').getBean('whatever') ); //return instance return this; </cfscript> </cffunction>
Anatomy of an Event Handler Method
As we discussed before a handler cfc contains several public/remote methods that can be executed by the framework. You can name these methods in any way you like as long as they make sense, naming is important for readability. With these methods you can call business logic, validate input, call plugins, etc. Well, so how do I do this? Each method will receive the request context object named Event as a parameter, which contains the request collection that we went over in the ColdBox overview guide and the request collection guide. If you have not read these guides, please do so now. This object contains the incoming request's data such as FORM/URL/REMOTE variables, the event requested, the view to render, the layout to render and any variables that your methods place in it. You can look at the CFC API to see all the methods that you have available in this object. The event object is the main object that you will be talking to in order to set/get data that can be shared in a request, set the layout or views to render, call plugins and more.
NOTE: The name of the argument received is Event of type coldbox.system.beans.requestContext
//public Event <cffunction name="{Method Name}" access="public" returntype="void" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> </cffunction> //private Event <cffunction name="{Method Name}" access="private" returntype="void" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> </cffunction>
Event Caching
To learn more about event caching, please read the caching guide. In summary, event caching is the concept of caching what an event produces as HTML. For example, you have an event called blog.showEntry. This event executes, gets an entry from the database and sets a view to be rendered. The framework then renders the view and if event caching is turned on for this event, the framework will cache the HTML. So the next incoming show entry event will just spit out the cached html. Important to note also, that any combination of url parameters on an event will produce a unique cacheable entry. So event=blog.showEntry&id=1 & event=blog.showEntry&id=2 are two different events.
The way to set up an event for caching is on its cffunction declaration with the following extra arguments:
| ATTRIBUTE | TYPE | DESCRIPTION |
| cache | boolean | A true or false will let the framework know whether to cache this event or not. The default is FALSE. |
| cachetimeout | numeric | The timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default object timeout in the cache settings. You can place a 0 in order to tell the framework to cache the event's output for the entire application timeout controlled by coldfusion, NOT GOOD. Always set a decent timeout for content. |
| cacheLastAccesstimeout | numeric | The last access timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default last access object timeout in the cache settings. This tells the framework that if the object has not been accessed in X amount of minutes, then purge it. |
Now, for more information on how to use this and how to purge events, please read the Caching Guide.
//Sample event caching <cffunction name="showEntry" access="public" returntype="void" output="false" cache="true" cacheTimeout="30" cacheLastAccessTimeout="15"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <cfscript> var rc = event.getCollection(); //get Entry rc.entry = getEntryService().getEntry(event.getValue('entryID',0)); //set view event.setView('showEntry'); </cfscript> </cffunction>
Method Samples
Can you show me an example of a method in real life? Sure, here are some examples from the ColdBoxReader application:
<cffunction name="index" access="public" returntype="void" output="false" cache="true" cacheTimeout="10"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <!--- Reference to the request collection ---> <cfset var rc = event.getCollection(); <!--- set a variable in the request collection ---> <cfset rc.myName = "Luiggi Majano"> <!--- Set the view to render ---> <cfset event.setView('home')> </cffunction> <cffunction name="onException" access="public" returntype="void" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <!--- My own Exception Handler ---> <!--- Log error ---> <cfset var exceptionBean = Event.getValue("ExceptionBean")> <!--- Do per Type Validations, example here ---> <cfif exceptionBean.getType eq "Framework.SettingNotFoundException"> <cfset getPlugin("messagebox").setMessage("warning", "Settings not found by my funky code.")> <!--- Relocate to default event, by not passing an event to the setnextevent method ---> <cfset setNextEvent()> <cfelse> <!--- Else, just log the errors and finalize execution, the framework then presents an error page---> <cfset getPlugin("logger").logErrorWithBean(exceptionBean)> </cfif> </cffunction> <cffunction name="doCreateAccount" access="public" returntype="void" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <cfscript> var password2 = Event.getValue("password2",""); var userService = getPlugin("ioc").getBean("userService"); var userBean = userService.createUserBean(); //Get a reference to the request collection for shorter typing, I am lazy. var rc = Event.getCollection(); //Populate Bean From Request Collection via the beanfactory plugin userBean = getPlugin("beanFactory").populateBean(userBean); if ( userBean.getUserName() eq "" or userBean.getPassword() eq "" or userBean.getemail() eq ""){ getPlugin("messagebox").setMessage("warning", "Please enter all the account information in order to create an account."); setNextEvent("ehUser.dspSignUp"); } if ( compare(UserBean.getpassword(),password2) neq 0 ){ getPlugin("messagebox").setMessage("warning", "The passwords do not match."); setNextEvent("ehUser.dspSignup"); } try { userService.saveUser(userBean); userBean.setVerified(true); //set session object getPlugin("sessionstorage").set("oUserBean",userBean); //relocate setNextEvent("ehGeneral.dspReader"); } catch (any e) { getPlugin("messagebox").setMessage("error", e.message & "<br>" & e.detail); //Call internal event by passing the request context dspSignUp(Event); //or you can use the runEvent method //runEvent("ehUser.dspSignUp") } </cfscript> </cffunction>
How to set and get values (Event Handlers, Views, Layouts)
In order for any event handler to work, it needs values. Most likely url parameters, form submissions or application/session/client variables. The framework provides you with a request collection structure for all your variable needs, modeled after the requestContext object. This object gets passed in to every event handler method with the argument name of event and type coldbox.system.beans.requestContext. The object also gets prepared for usage in your views and layouts as event and a reference to the request collection as a scope named rc. Below is an example of a event handler method using the request collection.
<cffunction name="dspHome" access="public" returntype="void" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <!--- Do Your Logic Here to prepare a view ---> <cfset Event.setValue("welcomeMessage","Welcome to ColdBox!")> <!--- Set the View To Display, after Logic ---> <cfset Event.setView("home")> </cffunction>
- getValue ( name, defaultValue )
- name: The name of the variable to return from the collection
- defaultValue: The default variable to return if the variable is not found in the collection. Since there are no default values that can be set for complex variables, you can send the following action keywords to return an empty complex variable according to the keyword. Please note that you need to pass in the keyword in brackets. Else the regular expression match will fail and the simple value will be returned.
- [array]
- [struct]
- [query]
- setValue ( name, value )
- name: The name of the variable to set in the reqCollection.
- value: The value of the variable (simple or complex)
- getCollection() : Returns the entire request collection data structure. Very useful to send in to the business layers or create a reference scope.
- paramValue(name, value) : This method checks if the name exists in the collection, if not, then it creates it with the value.
- removeValue(name) : Remove a value from the collection
- valueExists(name) : Checks if the value exists in the collection.
<cfscript> //Creating a reference scope var rc = event.getCollection(); //set a value event.setValue("name", "Luis"); //param a value event.paramValue("user_id",""); //remove a value event.removeValue("name"); //check if value exists if( event.valueExists("name") ){ } </cfscript>
So if you need to retrieve a value from a form POST or URL parameters, then you will use the event.getValue() method. If you need to store values into the collection in order for the views and layouts to access them, use the event.setValue() method. Pleas view the API to learn more about the event object.
How to relocate to another event
The framework provides you with two methods that you can use to relocate to other events, 1 for both normal and ses urls and another for only ses urls:
- setNextEvent([string event], [string queryString], [boolean addToken], [string persist], [struct varStruct], [boolean ssl],[string baseURL])
- setNextRoute(string route, [string persist], [struct varStruct],[boolean addToken],[boolean ssl])
setNextEvent
The setNextEvent method can be used for both normal and ses urls, here are its parameters:
| Argument | Required | Type | Description |
| event | false | string | The event to relocate to, if empty it defaults to the default event. ex: main.home |
| queryString | false | string | The query string to append to the relocation |
| addToken | false | boolean | Whether to add the cf tokens or not. Default is false |
| persist | false | string(list) | A comma-delimited list of request collection key names that will be flash persisted in the framework's flash RAM and re-inflated in the next request. |
| varStruct | false | struct | A structure of key-value pairs that will be flash persisted in the framework's flash RAM and re-inflated in the next request. |
| ssl | false | boolean(false) | Flag indicating if redirect should be done in ssl mode or not |
| baseURL | false | string | If used, then it is the base url for normal syntax redirection instead of just redirecting to the index.cfm |
All the arguments above are pretty straightforward except: persist & varStruct. Persist can be a comma-delimited list of request collection' key names that you want to persist in the internal flash memory of the framework for the relocation.varStruct is a structure of key-value pairs that will be persisted across a request. So when the user get's relocated, those variables (can be simple, complex, or even objects) will be flash stored and re-inflated back to the request collection on the relocation. Very useful to silently keep state on temporary objects.
setNextRoute
The setNextRoute method can be used for ses urls and it can use the following arguments:
| Argument | Required | Type | Description |
| route | true | string | The route to relocate to. ex: main/home |
| persist | false | string(list) | A comma-delimited list of request collection key names to persist in the relocation |
| varStruct | false | struct | A structure of key-value pairs that will be flash persisted in the framework's flash RAM and re-inflated in the next request. |
| addToken | false | boolean(false) | Flag to add the CF tokens to the redirection |
| ssl | false | boolean(false) | Flag indicating if redirect should be done in ssl mode or not |
In order to understand routes in ColdBox, please refer to the SES and Pretty URL guide. It will explain how you can use these incredible routing system.
Setting Views
The event object is the object that will let you set the views that you want to render, so please explore its api and the request collection guide. To quickly set a view to render, do the following:
<cfset event.setView('view')>
The view name is the name of the template in the views directory without appending the .cfm. So if the view is inside another directory you would do this:
<cfset event.setView('mydirectory/myView')>
You can also do caching of views, for that read the caching guide.
What if I don't want to render anything?
Well, if you don't want to, then you don't have to. The framework gives you a method in the event object that you can use if maybe this specific request should just terminate gracefully and not render anything at all. All you need to do is use the event object to call on the noRender() method.
<cfset event.noRender()>
This method tells the framework that this request will not produce any output, so just finalize the request. Most likely you will end up with a white page or if called from ajax, nothing.
Rendering Data
You can also use the event.renderData() method to render and marshal data directly from an event handler without the need to set a view for rendering. You do this via the renderData() method in the event object and you can read all about it in the Ajax Guide?.
//render a structure as JSON <cfset event.renderData(type='JSON', data=myStruct)> //render as WDDX <cfset event.renderData(type='WDDX', data=myStruct)> //render plain data. <cfset event.renderData(type='plain', data="Hello")>
Event Default Action
The event default action setup by the framework is index. What this means, is that if the framework detects that an incoming event has no action attached to it, it should look for a method in that handler called index. If it exists, then it will execute it as the incoming event. You can change the name of this default action in your configuration file or via the settings.xml file. In future versions, you will be able to define the default action that can be specific to each handler, as of now, its application wide. So for example, if we have an event handler called users and we call it like so:
index.cfm?event=users or index.cfm/users
The framework will look in the users handler for the index method. If it finds it, then it will treat the request as users.index. This is a very nice cool feature that can let you do some implicit declarations.
<cffunction name="index" returntype="void" access="public"> <cfargument name="event"> </cffunction>
Event Handler Implicit Events: preHandler, postHandler
There are also two implicit events that can be declared in your event handler that the framework will use in order to execute them anytime an event is fired from the current handler. This is great for intercepting calls and for pre/post processing before any type of event. If you declared them, the framework will execute them. (See Request Life Cycle)
| preHandler | Executes before the requested event (In the same handler cfc) |
| postHandler | Executes after the requested event (In the same handler cfc) |
Example:
<cffunction name="preHandler" output="false" returntype="void" access="public"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <cfscript> //Execute any pre-event code here. Like AOP logging, etc. </cfscript> </cffunction> <cffunction name="postHandler" output="false" returntype="void" access="public"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <cfscript> //Execute any post-event code here. Like layout considerations, etc. event.setLayout('Layout.PDF'); </cfscript> </cffunction>
Pre Handler Exception and Only Lists
The event handlers have some public properties that can be used to modify the preHandler interception method.
- You can define an exception list of actions for the event handler's preHandler() method by using the this.prehandler_exception property.
- You can define an execution only list of actions for the event handler's preHandler() method by using the this.prehandler_only property.
<!--- Execute the prehandler() method only for the private action ---> <cfset this.prehandler_only = "private"> <!--- Do not execute the preHandler() method for the login,logout and dspLogin actions ---> <cfset this.prehandler_exception = "login,logout,dspLogin">
Post Handler Exception and Only Lists
The event handlers have some public properties that can be used to modify the postHandler interception method.
- You can define an exception list of actions for the event handler's postHandler() method by using the this.posthandler_exception property.
- You can define an execution only list of actions for the event handler's postHandler() method by using the this.posthandler_only property.
<!--- Execute the posthandler() method only for the private action ---> <cfset this.posthandler_only = "private"> <!--- Do not execute the posthandler() method for the login,logout and dspLogin actions ---> <cfset this.posthandler_exception = "login,logout,dspLogin">
onMissingAction convention
Again, the power of conventions. With this convention you can now create virtual events that do not even need to be created or exist in a handler. Every time an event requests an action from an event handler and that action does not exists in the handler, the framework will check if an onMissingAction() event action has been declared. If it has, it will execute it. This is very similar to ColdFusion's onMissingMethod but on an event-driven framework.
Below is the skeleton for such an event action:
<!--- onMissingAction ---> <cffunction name="onMissingAction" access="public" returntype="void" output="false" hint="on missing action"> <cfargument name="Event" type="coldbox.system.beans.requestContext" required="yes"> <cfargument name="missingAction" required="true" type="string" hint=""> <cfset var rc = event.getCollection()> <cfscript> </cfscript> </cffunction>
This event has an extra argument: missingAction which is the missing action that was requested. You can then do any kind of logic against this missing action and decide to do internal processing, error handling or anything you like. The power of this convention method is extraordinary, you have tons of possibilities as you can create virtual events on specific event handlers. A good sample is for example a wiki processing page. You can have a route declared like this:
/wiki/page_name
Then have a wiki handler with the onMissingAction() method. Every time a page is requested, you can execute the onMissingAction() and render the correct page.
Handler Public Property: this.EVENT_CACHE_SUFFIX
This property is great for adding your own dynamic suffixes when using event caching. All you need to do is create a public property called EVENT_CACHE_SUFFIX and populate it with something you want. Then the event caching mechanisms will automatically append the suffix and thus create event caching using this suffix for the entire handler.
<cfset this.EVENT_CACHE_SUFFIX = "My Suffix>
Persisting Flash Variables
As we shown before, you can use ColdBox's flash RAM persistence via the setNextRoute or setNextEvent methods. However, you have a third method that you can use to persist variables on-demand, persistVariables(). This method not only persists variables when you call it, but you can call it multiple times in a request and it will keep appending to the persistence struct (Just be careful not to override stuff).
- persistVariables([string persist], [struct varStruct])
The two arguments can be by themselves or together if needed. The persist argument is a comma delimmitted list of keys of variables in the request collection to persist. Please note this, you pass in a list of keys that MUST exist in the request collection in order to exist. The varStruct argument is a structure of key-value pairs that you would like to append to the persistence structure. You can set variables anywhere you want, add it to this structure and then persist it.
rc.user_id = oUser.getUserid();
rc.salt = createUUID();
persistVariables(persist="user_id,salt");
myStruct = {user_id=oUser.getUserID(), salt=createUUID(), logindate=now()};
persistVariables(varStruct=myStruct);
Executing Events
Apart from executing events from the URL/FORM or Remote interfaces, you can also execute events, either public or private from within your event handlers. You do this by using the runEvent() method:
- runEvent([string event], [boolean prepostExempt], [boolean private])
Arguments
| argument | type | required | default | description |
| event | string | true | --- | The event to execute. |
| prepostExempt | boolean | false | false | If set to true, it will bypass any pre or post handler implicit executions. |
| private | boolean | false | false | If set to true, it will try to execute a private event. |
As you can see, you can execute events on demand with this method:
//public event <cfset runEvent('users.save')> //post exempt <cfset runEvent(event='users.save',prepostExemp=true)> //Private event <cfset runEvent(event='users.persist',private=true)>
Autowiring Your Handlers
You can easily autowire your handlers with objects coming from the IoC plugin or the coldbox cache by using the autowire interceptor. For a full hands on guide, please read the Autowire Guide as it will show you how to wire up your handlers with dependencies.
Best Practices
Organization
I always try to have some kind of mapping between the different logical sections or modules of my application and their event handlers. For example, if my application has a section for user management, with master and detail views, I'd create a single event handler cfc to hold all the methods related to that module. Now, large sections of your application that are more complex and have lots of actions and views, may require you to split the event handlers even more (like packages/directories), but the idea is the same.
The handler cfc's are also objects and therefore they should have their specific identity and function. So you need to map them in the best logical way according to their functions. If you need more flexibility you can even create directories (packages) and place them in logical buckets. This is mostly used in large applications as mentioned above. So think of them as entities and how they would do tasks for you via the events. Once you do this, you can come up with a very good cohesive event model for your applications. The application template creates two event handlers for you: main and general. The main contains mostly implicit methods for use in conjunction with the configuration file: coldbox.xml. The general is a general event handler and so forth.
In conclusion, organize your handlers as you would a domain model, put in practice your Ontology skills and define what these handlers will do for your, what is their identity.
Executing other events (Event Chaining)
The best practice on event execution would be via the runEvent() method. That is what is there for and it should be used. You can bypass it when calling methods in the same event handler. However, the best practice would be to use the provided method.
Init Method
Every handler does NOT need an init method, but if used, it must comply with the standard format shown in this guide. In that init method you can do whatever you want. If you want to set private properties to a handler, due composition of services, etc. You can.
Naming Conventions
Try always to add meaningful names to methods so other developers and users can understand what you are doing.
Advanced OO Features: UDF Injections
ColdBox provides you with a way to actually inject your event handlers with custom UDF's so you can change the behavior or expand on the behavior an event handler already has. This is called mixin methods and can be done via the includeUDF() method provided to every event handler or via the UDFLibrary setting in your coldbox.xml. The method is a provided way for you to dynamically load UDF's into your event handlers at runtime. You can do this in a specific method or at the initialization of the handler via the init() method. The sample below is using the init method:
<cffunction name="init" access="public" returntype="ehGeneral" output="false"> <cfargument name="controller" type="any" required="yes"> <cfscript> super.init(arguments.controller); //Any Code you like below //Load my special UDF's for my tools handler. includeUDF('includes/toolsUDF.cfm'); //return instance. return this; </cfscript> </cffunction>
The includeUDF method call will find the template and inject it to the handler.
There you go, that is dynamic loading of methods in your handlers. If you choose the route of the config file, you will declare the location of the UDF template to load into the handlers, layouts and views. That is the main difference between calling the includeUDF method and using the config setting.
