--
Peter J. Farrell
pe...@mach-ii.com
p...@maestropublishing.com
http://blog.maestropublishing.com
Identi.ca / Twitter: @maestrofjp
> This is worrying to me as I build my applications so that
> non-action pages (listing screens, managers, etc) can be refreshed
> without causing a problem. With these variables deleted after first
> request, that is no longer possible.
>
> Normally I've only persisted things such as response codes to show the
> user a message, so refreshing would cause the message to disappear,
> which wasn't a bit deal. However now I am persisting a special key
> through my redirections, and the process would be broken if the user
> ever refreshed.
Put that key in the URL. Use the "args" attribute of <redirect> or the
args argument of RedirectEvent() to stick an additional key in the URL.
.pjf
<!---
Notes:
* Uses the "id" key in the url
Params:
elementProperty = Name of the event-arg to place the data into
redirectEvent = The event to redirect to if there is no active ID element
--->
<cfcomponent
displayname="getElementByIdFilter"
extends="MachII.framework.EventFilter"
depends="sessionFacade,udfs"
output="false"
hint="Gets elements from the session facade by id.">
<!---
PUBLIC FUNCTIONS
--->
<cffunction name="filterEvent" access="public" returntype="boolean"
output="false"
hint="Runs the filter event.">
<cfargument name="event" type="MachII.framework.Event" required="true" />
<cfargument name="eventContext" type="MachII.framework.EventContext"
required="true" />
<cfargument name="paramArgs" type="struct" required="true" />
<cfset var id = arguments.event.getArg("id", "") />
<!--- Get the bean if it is defined --->
<cfif getUdfs().isUUID(id) AND getSessionFacade().isElementByIdDefined(id)>
<cfset arguments.event.setArg(arguments.paramArgs.elementProperty,
getSessionFacade().getElementById(id)) />
<cfreturn TRUE />
<cfelse>
<cfset RedirectEvent(arguments.paramArgs.redirectEvent) />
<cfreturn FALSE />
</cfif>
</cffunction>
</cfcomponent>
Session Facade:
<cffunction name="formatUUID" access="private" returntype="string"
output="false"
hint="Formats a uuid into a safe format to as a variable.">
<cfargument name="id" type="uuid" required="true" />
<cfreturn "_" & Replace(arguments.id, "-", "_", "ALL") />
</cffunction>
<cffunction name="isElementsDefined" access="public"
returntype="boolean" output="false">
<cfreturn IsDefined("session.user.elementsById") />
</cffunction>
<cffunction name="setupElements" access="private" returntype="void"
output="false"
hint="Setups the elements service.">
<cfset session.user.elementsById.lastCleanup = DateConvert("local2UTC",
Now()) />
<cfset session.user.elementsById.data = StructNew() />
<cfset session.user.elementsById.timestamps = StructNew() />
</cffunction>
<cffunction name="cleanupElements" access="private" returntype="void"
output="false"
hint="Cleans up left over elements.">
<cfset var sorted = "" />
<cfset var datetime = DateConvert("local2UTC", Now()) />
<cfset var i = "" />
<!--- Check if cleanup if is required and do double lock --->
<cfif DateDiff("s", getElementLastCleanup(), datetime) GTE 600>
<cflock name="sessionFacade_cleanupElements_#session.cfid#" timeout="1"
throwontimeout="false">
<cfif DateDiff("s", getElementLastCleanup(), DateConvert("local2UTC",
Now())) GTE 600>
<!--- Reset the last cleanup --->
<cfset resetElementLastCleanup() />
<!--- Get sorted list --->
<cfset sorted = StructSort(session.user.elementsById.timestamps, "text",
"ASC") />
<!--- Loop through and delete --->
<cfif ArrayLen(sorted)>
<cfloop from="1" to="#ArrayLen(sorted)#" index="i">
<cfif DateDiff("s", sorted[i], datetime) GTE 1800>
<cfset StructDelete(session.user.elementsById.data,
session.user.elementsById.timestamps[sorted[i]], FALSE) />
<cfset StructDelete(session.user.elementsById.timestamps, sorted[i],
FALSE) />
<cfelse>
<cfbreak />
</cfif>
</cfloop>
</cfif>
</cfif>
</cflock>
</cfif>
</cffunction>
<cffunction name="resetElementLastCleanup" access="private"
returntype="void" output="false">
<cfset session.user.elementsById.lastCleanup = DateConvert("local2UTC",
Now()) />
</cffunction>
<cffunction name="getElementLastCleanup" access="public"
returntype="date" output="false">
<cfreturn session.user.elementsById.lastCleanup />
</cffunction>
<cffunction name="getElementCount" access="public" returntype="numeric"
output="false">
<cfreturn StructCount(session.user.elementsById.data) />
</cffunction>
<cffunction name="makeElementTimestamp" access="private"
returntype="void" output="false"
hint="Makes a timestamp for element. Deletes old keys.">
<cfargument name="id" type="uuid" required="true" />
<cfset var stamps =
StructFindValue(session.user.elementsById.timestamps,
formatUUID(arguments.id), "ALL") />
<cfset var i = "" />
<cfloop from="1" to="#ArrayLen(stamps)#" index="i">
<cfset StructDelete(session.user.elementsById.timestamps, stamps[i].key,
FALSE) />
</cfloop>
<cfset session.user.elementsById.timestamps[DateConvert("local2UTC",
Now())] = formatUUID(arguments.id) />
</cffunction>