To start off, I am a pretty big advocate of the Mach-II framework and entirely biased for its use. I’ve been using Mach-II for almost 2 years now and have loved every second of it. My background has been Java development, so I’m no stranger to object-oriented design, which Mach-II really prides itself on.
One of the biggest frustrations in ColdFusion-land, for me anyway, was the fact that everything was procedural. Meaning, the more code that you wrote, the more it would start to resemble something you’d find on your plate at your favorite Italian restaurant. Prior to using Mach-II I really pushed my peers into making use of as many CFC’s as possible, essentially generating my own framework of sorts.
Enter Mach-II
Mach-II was definitely an eye-opener for me. It is a highly-structured framework which promotes excellent MVC (model-view-controller) usage, allows modular development (think: reuse the same code over and over again for more than one project), and makes maintenance much easier.
It was a lot to swallow from the get-go and involved a bit of a change of perspective. Event driven? Views? Listeners? Filters? Plugins? It was all very confusing from the start, but once you wrap your mind around it, it’s a fantastic set of tools to aid any ColdFusion developer in their development and maintenance cycles.
Some of the key benefits of using a framework such as Mach-II:
- Enforces an object-oriented, MVC design for your code
- Provides a great structure for modular code
- Makes maintenance easier
- Provides a large library of helper functions to aid in rapid application development
How it Works
As mentioned above, Mach-II is event-driven. In a nutshell, you define a set of views and operations that affect those views within an XML file, which together are called an event, and simply call upon that event via a web browser and you’re done. It’s really that easy.
XML may seem like a strange place to put this configuration data, but in reality who really enjoys hunting through spaghetti code with multiple includes to find what you’re looking for. With the XML configuration file, it’s all right there, and structured so it’s simple to understand.
<mach-ii> <event-handlers> <event-handler name="helloWorld" access="public"> <view-page name="hello" /> <view-page name="world" append="true" /> </event-handler> </event-handlers> <page-views> <page-view name="hello" value="views/hello.cfm" /> <page-view name="world" value="views/world.cfm" /> </page-views> </mach-ii>
Above is a simple event called helloWorld which outputs a page consisting of two views (hello and world) appended together.
Views
Views consist of the visible portion of your web site. They contain all the HTML and content you wish displayed to your users. In proper MVC architecture, view pages perform as little logic as possible and do not make calls to the database (for example). Their purpose is simply to output information based on content provided to them.
<cfset contentQuery = request.event.getArg('myQuery') />
<cfoutput>
<h1>#request.event.getArg('pageTitle')#</h1>
<cfloop query="contentQuery">
<p>#contentQuery.content#</p>
</cfloop>
</cfoutput>
As you can see in the example above, information is passed to this view using an Event object. This is a Mach-II construct used to store and pass along information to each part of your application.
Views are defined in the Mach-II configuration file under the <page-views> tag:
<mach-ii> <page-views> <page-view name="hello" value="views/hello.cfm" /> <page-view name="world" value="views/world.cfm" /> </page-views> </mach-ii>
Listeners
In essence, a listener’s job is to provide a connection between Mach-II (which is the controller part of MVC) and your model (which handles all of the logic for your application). The listener receives the Event object and determines what (if anything) to do with the state of the content within it. It then can call upon your model layer to perform any necesary operations or to gather additional data.
Common uses for listeners include:
- Getting query data from the model and placing it into the event for use in a view
- Sending login information to a service to detect whether the information provided is valid
- Announcing a new event based on the input provided
It’s good practice to ensure that any Mach-II specific code which accesses your model is kept out of your service layer and within listeners. The idea is that your controller layer (Mach-II) is constructed in such a way that it’s relatively easy if you ever wish to change it with a different controller. Keeping Mach-II specific methods and logic within your listeners is a great way to achieve this.
<mach-ii> <listeners> <listener name="myListener" type="path.to.myListener" /> </listeners> <event-handlers> <event-handler name="helloWorld" access="public"> <notify listener="myListener" method="getMyQuery" resultArg="myQuery" /> <view-page name="hello" /> <view-page name="world" append="true" /> </event-handler> </event-handlers> </mach-ii>
In the example above our listener myListener is defined in the listeners section. We can then access any of the listener’s methods using the notify tag. In our case, we’re calling the getMyQuery method and storing the result within myQuery to be used later (in a view, for example).
Filters
Event filters are similar to listeners in the fact that they receive information regarding the event and its status, and will perform some logic to determine what happens next. Where the listener is mainly used to interact with the model and set some event arguments to be used later in the event stack, filters have the added ability of dynamically controlling the event itself and how it processes.
A filter has the ability to stop execution of an event if certain criteria aren’t met, dynamically call a subroutine (not covered here) or call upon another event.
Common uses for filters include:
- Determine if a user is logged in, and redirect to the login page if the credentials do not match
- Validate a form and redirect the event accordingly (back to the entry form again if there are errors, or to a success page if everything checks out
- Execute a subroutine that could act as a widget in your web application
<mach-ii> <event-filters> <event-filter name="myFilter" type="path.to.myFilter" /> </event-filters> <event-handlers> <event-handler name="helloWorld" access="public"> <filter name="myFilter" /> <notify listener="myListener" method="getMyQuery" resultArg="myQuery" /> <view-page name="hello" /> <view-page name="world" append="true" /> </event-handler> </event-handlers> </mach-ii>
The example above creates myFilter which resides at path.to.myFilter, and calls it at the beginning of the event named helloWorld.
Plugins
Plugins are somewhat similar to both listeners and filters, but are run on every request within the application. There are various plugin points that you have access to:
| preProcess | executed at the beginning of the request before Event processing begins |
| preEvent | executed before each Event |
| postEvent | executed following each Event |
| preView | executed before each View |
| postView | executed following each View |
| postProcess | executed following all Event processing |
| handleException | when an exception occurs |
There are two other plugin points that aren’t necessarily run on every request:
| onSessionStart | when a session starts |
| onSessionEnd | when a session ends |
Plugins have several common uses, but are not restricted to:
- Checking login status and loading additional objects depending on state
- Loading common variables to be used on each event
- Detecting form or url variables to logout a user and performing the necessary operations to do so
<mach-ii> <event-handlers> <event-handler name="helloWorld" access="public"> <filter name="myFilter" /> <notify listener="myListener" method="getMyQuery" resultArg="myQuery" /> <view-page name="hello" /> <view-page name="world" append="true" /> </event-handler> </event-handlers> <plugins> <plugin name="myPlugin" type="path.to.myPlugin" /> </plugins> </mach-ii>
Above is an example of configuring a plugin to be used within your Mach-II application.
And There’s More…
Mach-II provides a lot more functionality than what was explained above, plus you can get much more detail on these methods and more at Mach-II.com. Hopefully this article gave you a brief overview of what makes up a Mach-II application and some of ways it’ll help you in your application development.
Tags: beginner, event, filter, listener, Mach-II, plugin, view
