Version 9 (modified by cfgrok, 16 years ago)

Added redirect attribute to result tags -- cleaned up formatting & corrected typos

How To Use Typed Events

Every Model-Glue developer eventually asks themselves this question: "How do I do something on every event?" What that something is, can vary, of course, but some common examples would be:

How do I apply security to every event in my application?

How do I apply a template to every event in my application?

And, of course, there is the more complicated variation on this:

How do I apply something to a subset of events on my application?

Traditionally, if you were trying to, for example, apply security to every event in your application you would simply broadcast a message that would check security and add results to map to a login page or access denied page. The obvious problem here is the repetitive nature of the XML as well as the need to manually it to every event you wish to secure.

A more advanced, alternative, technique would be to override the ModelGlue.OnRequestStart event handler and use that to broadcast your messages and apply your results. In this case the problem would be controlling the scope so that events are properly secured. You wouldn't, for example, want to secure your login page… that wouldn't work very well.

Model-Glue 3 provides a new feature, Typed Events, to make the process of applying configuration selectively to specific events quite easy. Typed events allow you to create a template for a set of messages, results, and includes which need to be processed before or after messages, results and includes are executed in an event handler.

This feature allows developers to easily create sets of XML which would have traditionally been spread across many event handlers.

Typed Events are defined in an <event-types> section of the ModelGlue.xml file. This tag is at the same level as the <event-handlers> tag. The <event-types> tag contains multiple <event-type> tags which can, themselves, contain <before> and or <after> tags. The <before> and or <after> hold the same child tags as a standard <event-handler> tag.

Additionally, you may also define a default event type, or set of event types to an <event-handlers> block like this <event-handlers defaultType="MyDefaultEventType">. A defaultType will apply to all child <event-handler> blocks within the body of the specific <event-handlers> tag. (more below).

Here's an example ModelGlue.xml document:

<modelglue>
    <controllers>
        <!-- controllers are defined here -->
    </controllers>
    <event-types>
        <event-type name="example">
            <before>
                <!-- broadcasts, results, and views tags go here -->
            </before>
            <after>
                <!-- broadcasts, results, and views tags go here -->
            </after>
        </event-type>
    </event-types>
    <event-handlers>
        <!-- event handlers are defined here -->
    </event-handlers>
</modelglue>

For more on the tag hierarchy see the API documentation.

So, using this tag hierarchy, we can define an event type that would secure the event handler. Here is the XML to define this event type.

<event-type name="SecuredEvent">
    <before>
        <broadcasts>
            <message name="LoginRequired" />
        </broadcasts>
        <results>
            <result name="NotLoggedIn" do="user.login" redirect="true" />
        </results>
    </before>
</event-type>

This event type is used by specifying the type attribute of the <event-handler> tag. For example:

<event-handler name="home.page" type="SecuredEvent">
    <broadcasts>
        <message name="NeedSomeReport" />
    </broadcasts>
    <views>
        <include name="home" value="home.cfm" />
    </views>
</event-handler>

When the ModelGlue.xml configuration file is loaded by the framework, the event-handler will logically be converted to this XML:

<event-handler name="home.page">
    <broadcasts>
        <message name="LoginRequired" />
        <message name="NeedSomeReport" />
    </broadcasts>
    <results>
        <result name="NotLoggedIn" do="user.login" redirect="true" />
    </results>
    <views>
        <include name="home" value="home.cfm" />
    </views>
</event-handler>

As you can see, everything in the <before> tag in the <event-type> tag is handled before any thing else in the <event-handler>. This would be true of included views as well.

You can also use the <after> tag to define broadcasts, results and views which will be run after an event handler's broadcasts, results and views are run. Here's a typed event example that would apply a template to an event handler:

<event-types>
     <event-type name="TemplatedEvent">
        <after>
            <views>
                <include name="main" template="templates/main.cfm" />
            </views>
        </after>
    </event-type>
</event-types>

To apply that template to the same event above you would simply use the TemplatedEvent type as show below:

<event-handler name="home.page" type="TemplatedEvent">
    <broadcasts>
        <message name="NeedSomeReport" />
    </broadcasts>
    <views>
        <include name="home" value="home.cfm" />
    </views>
</event-handler>

This configuration will cause the template to be included as the last view and, thusly, the view that applies the template. Logically, this would result in the following <event-handler> XML:

<event-handler name="home.page">
    <broadcasts>
        <message name="NeedSomeReport" />
    </broadcasts>
    <views>
        <include name="home" value="home.cfm" />
        <include name="main" template="templates/main.cfm" />
    </views>
</event-handler>

You can apply more than one event type to an event handler. For example, we could define an event which is both secured and templated. Here's the configuration XML:

<event-handler name="home.page" type="SecuredEvent,TemplatedEvent">
    <broadcasts>
        <message name="NeedSomeReport" />
    </broadcasts>
    <views>
        <include name="home" value="home.cfm" />
    </views>
</event-handler>

When loaded, this configuration would result in this logical XML:

<event-handler name="home.page">
    <broadcasts>
        <message name="LoginRequired" />
        <message name="NeedSomeReport" />
    </broadcasts>
    <results>
        <result name="NotLoggedIn" do="user.login" />
    </results>
    <views>
        <include name="home" value="home.cfm" />
        <include name="main" template="templates/main.cfm" />
    </views>
</event-handler>

You can also provide a default event type as an attribute of your event-handlers tag which will apply the event-type to all child event handler tags.

<!-- declares the default event type -->
<event-handlers defaultType="MyDefaultEventType">
<!-- inherits the defaultType -->
  <event-handler name="page.1">
  </event-handler>

<!-- overrides the defaultType and only gets AnotherEventType -->
  <event-handler name="page.2" type="AnotherEventType">
  </event-handler>

<!-- removes the defaultType -->
  <event-handler name="page.3" type="">
  </event-handler>
</event-handlers>

<!-- no default type declared -->
<event-handlers>
<!-- apply event type individually  -->
  <event-handler name="page.3" type="AnotherEventType">
  </event-handler>
</event-handlers>

By using event types you can now save yourself a lot of repetitive configuration. This also helps avoid cases where you may need to update dozens of event handlers if you need to modify how your security system works.