Model-Glue Short URLs on the Cheap
I've blogged before about short, SES style URLs and what I use. (To summarize - I'd either recommend URL Rewriting in Apache or IIRF for IIS.) What if you can't use a web server side solution? You're left with using a solution I used for BlogCFC, namely appending values after the file name and using CGI.PATH_INFO to parse it. Here is a simple example.
CGI.PATH_INFO is a CGI variable that will represent any information found after the filename in the URL. Look at the URL in the browser. Notice the index.cfm is followed by a / and then various bit of information. What I did for BlogCFC was create a specific pattern, and then wrote some code to parse that pattern and load various groups of blog entries (or A blog entry) based on the value. I could have also done something a bit more generic of the form:
/name1/var1/name2/var2
In this pattern, I've changed name1=var1&name2=var2 to a simpler list of name/value pairs. We can use the same pattern with Model-Glue, but since Model-Glue uses an event value, we need to preface it with the event to run. So the pattern I will use is:
/event/name1/var1/name2/var2
I opened up my Application.cfm file and added the following code:
<!--- get the info --->
<cfif len(trim(cgi.path_info))>
<!--- From Michael Dinowitz --->
<cfset urlVars=reReplaceNoCase(trim(cgi.path_info), '.+\.cfm/? *', '')>
<cfif urlVars is not "" and urlVars is not "/">
<!--- remove first / --->
<cfif left(urlVars, 1) is "/">
<cfset urlVars = right(urlVars, len(urlVars)-1)>
</cfif>
<!--- Event is first item --->
<cfset url.event = listFirst(urlVars, "/")>
<!--- strip it off --->
<cfset urlVars = listRest(urlVars, "/")>
<!--- now build name/val pairs --->
<cfloop index="x" from="1" to="#listlen(urlVars,"/")#" step="2">
<cfset name = listGetAt(urlVars, x, "/")>
<cfif listLen(urlVars, "/") gte x+1>
<cfset value = listGetAt(urlVars, x+1, "/")>
<cfelse>
<cfset value = "">
</cfif>
<cfset url[name] = value>
</cfloop>
</cfif>
</cfif>
I'm not going to pick over this too much as you can see it is just string parsing. Basically I get the information after the /, grab the event as the first item, and if anything else is left than it is treated as name/value pairs. Also note that I support a name without a value. This would be useful for passing a "flag" type setting.
As a practical example, instead of using this URL:
/index.cfm?event=loadArticle&id=5
I can use this:
/index.cfm/loadArticle/id/5
For print format, I could use this:
/index.cfm/loadArticle/id/5/print
And to make it even nicer, I could include the title of the article in the URL. This would be used to help search engines, but have zero uses in the controllers:
/index.cfm/loadArticle/id/5/Dharma-Controls-All-Feed-The-Swan
Again - let me be clear - your best solution would be to use URL Rewriting, but this is an alternative you can use if that is not an option.
Comments
I've never run into that problem with IIS, but I am running my development on an WindowsXP platform. Maybe it was an issue in older versions, but shouldn't be if you're up-to-date.
<cfif urlVars is not "" and urlVars is not "">
It looks like the same test twice.. ?
The second condition was meant to be "/". Going to fix now. Thanks!
http://further.gregnilsen.com/index.cfm/module/sto...
http://corfield.org/entry/SES__Bah_Humbug
It works with any framework (or non-framework) because it's included in Application.cfm (or Application.cfm).
When I do the dump, it is getting populated. Do you call the url like this: #viewstate.getValue("myself")#theevent
For example,
The link reads "index.cfm/page.login". The user clicks it and goes to the login form.
The login form submits to "/index.cfm/action.login" and fires an event "user.login", if successful the result from that event does "page.index". The resulting URL looks like "http://localhost/index.cfm/index.cfm?event=page.in...;
Any idea how to properly redirect in the result?
There is one other thing. In a result, depending on success or failure, I fire another event. When I use "redirect=true" (<result name="success" do="page.index" redirect="true" />), the URL gets messed up again to http://localhost/index.cfm/index.cfm?event=page.in...
It works if I leave the redirect part out. I have tried different things in the "do" (/index.cfm/page.index, /page.index) part but I get errors.
Is this just the way this works?

