My solution to the Friday Puzzle

Based on my post from yesterday, here is my 5 minute 'quick stat' solution to the puzzle. Note, this is not thread safe and it will quickly destroy my server (most likely), but it works!

I added this to Application.cfm, at the bottom, before my last cfsetting.

<cffunction name="getCurrentURL" output="No" access="public" returnType="string"> <cfset var theURL = getPageContext().getRequest().GetRequestUrl().toString()> <cfif len( CGI.query_string )><cfset theURL = theURL & "?" & CGI.query_string></cfif> <cfreturn theURL> </cffunction> <cfset s = structGet("application.data")> <cfset p = getCurrentURL()> <cfif not structKeyExists(s, p)> <cfset s[p] = 0> </cfif> <cfset s[p]++>

The UDF comes from CFLib of course. It handles both query string and path_info CGI variables so it works well on the blog.

To display it, I wrote this script:

<cfset sorted = structSort(application.data,"numeric","desc")> <table width="100%" border="1" cellpadding="5"> <tr> <th>Page</th> <th>Count</th> </tr> <cfloop index="a" array="#sorted#"> <cfoutput> <tr> <td>#a#</td> <td>#numberFormat(application.data[a])#</td> </tr> </cfoutput> </cfloop> </table>

Nothing too complex here outside of the cool structSort function which works perfectly for this example. If you are bored, you can see this in action here.

Archived Comments

Comment 1 by Phillip Senn posted on 12/7/2008 at 1:39 AM

What does this stmt do?
<cfset s = structGet("application.data")>

According to the CFML reference, it returns
"An alias to the variable in the pathDesired parameter."
Which I think it means it simply creates a pointer, or a shortcut (ie: not a clone or copy of) the variable called "data" that is in the application scope.

The book then says:
If necessary, StructGet creates structures or arrays to make pathDesired a valid variable "path."
I'm not sure what the implications are for that.
But it almost sounds like it would create a clone, or a copy "if necessary".

What is the definition of a valid variable "path"?

Comment 2 by Phillip Senn posted on 12/7/2008 at 1:52 AM

Where did you learn about:
getPageContext().getRequest().GetRequestUrl().toString()?

Is this the equivalent to something more familiar?

Comment 3 by Phillip Senn posted on 12/7/2008 at 2:01 AM

<cfif not structKeyExists(s, p)>
<cfset s[p] = 0>
</cfif>
<cfset s[p]++>

Q: Can you use what looks like array notation on structures?

If the value of p="Index.cfm", then is this in effect saying:

<cfif not structKeyExists(s, "Index.cfm")>
<cfset s("Index.cfm") = 0>
</cfif>
<cfset s("Index.cfm")++>
?

Comment 4 by Raymond Camden posted on 12/7/2008 at 2:29 AM

Wow, a lot of questions.

1) structGet. structGet basically says, "If X doesn't exist, make it. Then return a pointer." So imagine X="application.foo.moo". CF will say "Does the Application struct exists?" If no, make it. Then it wil say, does Foo exist as a struct in Application? If not, make it.

And so on and so on.

It is basically a quick way to make a deeply nested struct. You can also do Application.foo[5], and it will create foo as an array.

2) getPageContext() - It's documented. :) That's in the CF ref, and then you get access to a Java object which is also documented. I didn't find this myself, it was in the UDF.

3) Your last question confuses me. You use bracket notation with structs, just like arrays, but arrays are only indexed by #s, structs are indexed by string based keys.