GET
requests are put into the url
scope and POST
parameters are put into the form
scope. While this makes sense technically, I find it kind of annoying. For the most part, I don't care where the parameters come from.Most ColdFusion frameworks alleviate this problem by combining the scopes for you. For example, Model-Glue and Mach-II create an
event
object that exposes parameters via event.getValue(key)
or event.getArg(key)
. FW/1 combines the variables into request.context
, which is then aliased as rc
inside your controllers and views. ColdBox does a little bit of both, by having event.getValue(key)
inside your controllers and rc
inside your views.While this makes working with request parameters easier, it still feels a little cumbersome having to go through getters and setters or cryptically-named structs (rc? really?). I'd rather have all the parameters combined into a single scope from the get-go.
One of the many things I like about Ruby on Rails and Grails is the
params
scope, which contains all GET
and POST
request parameters. Not surprisingly, CFWheels also has the params
scope.However, what happens if you're not using CFWheels, or even a framework at all? I want the same functionality, but without the overhead of adding a framework. With a little inspiration from Ben Nadel, here's my solution:
Application.cfc
component {
function onRequestStart() {
var params = {};
structAppend(params,url);
structAppend(params,form);
getPageContext().getFusionContext().hiddenScope.params = params;
}
}
Now all
url
and form
variables are combined into a single params
struct at the beginning of each request, which is then made globally accessible throughout my application, just like a built-in scope. Short and simple, no framework necessary.On a final note, while this does work, I don't know if all the ColdFusion "experts" would consider it a best practice to add a new "scope" to the language. But in my opinion, it's isolated and helps solve a problem, so why not?
Yeah, I don't really care for using the hiddenScope thing, but that's another discussion.
ReplyDeleteThe main thing you should point out in your example is that if duplicate keys exist then the form scope entry (again, in your example) will overwrite the url scope variable. That can be a bit tricky to folks who use this method.
@Todd,
ReplyDeleteGood point about duplicate keys. Most frameworks do mention that the form scope takes precedence over the url scope. I just didn't bother to point it out.
Another thing to mention would be that the form scope doesn't exist in WSDL-base remote requests, so you'd probably want to throw an isDefined('form') in there too.
Hmm, very interesting. I had never thought of using it in that respect.
ReplyDeleteI don't feel comfortable using getPageContext().getFusionContext().hiddenScope.params ...
ReplyDeleteIs this documented? or undocumented?
@Henry,
ReplyDeleteAccording to Ben's post it's undocumented.
For those of us who have worked with ColdBox, the rc scope isn't "cryptically named". It stands for "request collection." In earlier versions, you had to use event.getValue(key) in both controllers and views (and you still can do it that way). But it became a convention to do rc = event.getCollection() which returns a structure with all your request collection variables so you didn't have to use getters. Eventually, that "rc scope" was automatically made available to views.
ReplyDelete@blitz,
ReplyDeleteI've worked with ColdBox before and I'm familiar with the request collection. I would just prefer something a little more straight-forward than "rc", like "params". People new to the ColdBox framework probably have no clue what "rc" is, where they could take a pretty good guess if it were named "params".
Is this code put inside a cfscript tag within the onRequestStart component? I am one of these people that need every little detail spelled out before I can wrap my brain around it.
ReplyDeleteIn the example I'm using an Application.cfc written in script. The tag-based equivalent would be:
ReplyDelete<cfcomponent>
<cffunction name="onRequestStart">
<cfset var params = {} />
<cfset structAppend(params, url) />
<cfset structAppend(params, form) />
<cfset getPageContext().getFusionContext().hiddenScope.params = params />
</cffunction>
</cfcomponent>