Dynamically adding <views/> to a Model-Glue Event
Mark Drew hit me up with an interesting question this morning: can you dynamically add views to a Model-Glue event, determining which views to include at runtime, what to name them, and what template they should use? Yes, you can, and you can do it without mixing configuration information into the controller tier.
Background
Being a stubborn curmudgeon, I asked why he'd want to in the first place: it'd place configuration knowledge (names of templates, names of views) up in the controller tier.
Being a logical guy, he told me he was well aware of this, and outlined his situation. To spare you the details, I'll just say that I agree that adding views to the queue at runtime is necessary in his case.
The Solution
Disclaimer: I'd recommend avoiding situations where doing this is necessary, but it's good to know it can be done!
In a Model-Glue controller, if you <cfdump&/> arguments.event, you'll see that you're dealing with an instance of EventContext. It's got a method, getEventRequest(), that lets you hook into the underlying event request. Warning: you can really screw some stuff up by monkeying with the event request.
Red text aside, EventRequest has a method called addView(view:View) that lets you add views to the queue of views to be rendered.
All we need to do to keep Mark happy is to create an instance of ModelGlue.unity.eventhandler.View and add it to the queue:
<cfargument name="event" type="any">
<cfset var eventRequest = arguments.event.getEventRequest() />
<cfset var view = createObject("component", "ModelGlue.unity.eventhandler.View").init() />
<cfset view.setTemplate("dspSomeDynamicView.cfm") />
<cfset view.setName("dynamicView") />
<!--- Add our dynamic event to the queue of pending views to render --->
<cfset eventRequest.addView(view) />
</cffunction>
That's kind of sloppy, though: in Model-Glue 2.0, you can achieve a very high degree separation of configuration from code. Because it's ok to instantiate a View as a singleton (it's just metadata), we can define this view as a ColdSpring bean, autowiring it into our controller.
Here's the code:
ColdSpring
<!-- Just like the name attribute on <view>! -->
<property name="name"><value>dynamicView</value></property>
<!-- This'll use the viewMappings setting just like a normal view! -->
<property name="template"><value>dspSomeDynamicView.cfm</value></property>
</bean>
Controller
<cffunction name="setSomeDynamicView">
<cfargument name="someDynamicView" />
<cfset variables._someDynamicView = arguments.someDynamicView />
</cffunction>
<cffunction name="queueDynamicViews" access="public" returnType="void" output="false">
<cfargument name="event" type="any">
<cfset var eventRequest = arguments.event.getEventRequest() />
<cfset eventRequest.addView(variables._someDynamicView) />
</cffunction>
</cfcomponent>

