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.
Archived Comments
That's more or less what I've been doing for almost a year now over at my site, though I don't think my code is quite as long. I like doing it that way because it's very flexible.
I recall there being an issue with IIS lockdown blocking these requests due to the period in what it initially believes is the directory name. Possibly addressed in newer versions (allowing a single period in a directory but rejecting two), I really don't know, but if anyone runs into a problem handling this request it may be relevant.
Michael,
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.
Just wondering about the 2nd cfif:
<cfif urlVars is not "" and urlVars is not "">
It looks like the same test twice.. ?
Despite the fact that IIRF is free, I would advice to go with ISAPI Rewrite. It's well worth the few $$. One of the main features that IIRF didn't have was the [U] directive -- unmangle logs files, meaning, log the request prior to the rewrite ... which was essential for me.
Um, it was a test Michael. ;)
The second condition was meant to be "/". Going to fix now. Thanks!
In the release notes, I do see a U directive Rob. So maybe he has added that in?
It may/probably have been added. I remember chatting with him when you first blogged about it and he said it wasn't difficult to add. Good to know; danke,
Very nice Ray. Got it implemented already! Love the use of the step attribute in cfloop.
Ok, now that I'm home I could get at my code. I've posted what I've been using on my blog here:
http://further.gregnilsen.c...
I posted the code for how I do SES URLs on my (Fusebox) site back in September last year:
http://corfield.org/entry/S...
It works with any framework (or non-framework) because it's included in Application.cfm (or Application.cfm).
I tried implementing the code into my Application.cfm file but it doesn't do anything. Am I missing something?
Chris - what do you see? You should also cfdump url and see if it is getting populated correctly.
Ray,
When I do the dump, it is getting populated. Do you call the url like this: #viewstate.getValue("myself")#theevent
No, you need to make the URLs yourself. Unless you make a helper function for it.
I tried using this code. It worked mostly. Where I have trouble is in the modelglue.xml file. When an event fires and I point to another event it seems to just the events together.
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.index"
Any idea how to properly redirect in the result?
You said your first link was to index.cfm/page.login. It needs to be /index.cfm/page.login. Did you use that?
Thanks Ray, that was part of my problem.
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.index
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?
@Ross, yes, redirects use regular URLs. That's how it's built inside Model-Glue. Since people are unlikely to bookmark the result of a form post (which is when you mostly use redirect="true"), I don't see that as a big problem.