getDirectoryFromMapping function to solve a problem with expandPath()

Originally Posted At : September 11, 2008 7:36 AM

I recently found a bit of a problem with some of the code at work. We use coldspring, transfer and model-glue, embedded into our own CMS/Framework. The config system in our framework injects various database and xml file variables. These settings use ColdFusion mappings. Eventually, these variables end up in a function somewhere that creates directories for missing folders. These functions generally use expandPath() to turn the mapping into a filepath and then check to see if the directory exists. Only trouble is expandPath() has been returning the full file path for the calling template when the directory doesn't exist.

I'm not sure when this started happening, but, basically, if you have a mapping say "/myapp" and you want a "temp" directory under that mapping, so the mapping would be "/myapp/temp". This mapping doesn't actually exist in CF. "/myapp" points to a real folder, say "c:\apps\myapp", but "c:\apps\myapp\temp" doesn't exist either. When you expandPath("/myapp/temp") it is returning the calling template name and path rather "c:\apps\myapps\temp".

This was further complicated by the fact that we have apache rewrite rules that redirect file paths to handlers files. ExpandPath() is returning the handler filename and path, but getBaseTemplatePath() is returning the page that was originally called eg. index.cfm rather than handler.cfm.

After trying a bunch of things and asking around I couldn't resolve this issue using existing coldfusion functions. With a reminder from a colleague of the existance of coldfusion's service factory and that you can get a list of all the mappings, I eventually came up with this function.

<cffunction name="getDirectoryFromMapping" >
	<cfargument name="mapping" type="string" required="true" >
	<cfset var stMappings = createObject("java","coldfusion.server.ServiceFactory").getRuntimeService().getMappings() >
	<cfset var mappingDir = "" >
	<cfset var mappingKeys = "" >
	<cfset var thisKey = "" >
	<cfset var theEnd = "" >
	<cfif structKeyExists(stMappings,arguments.mapping)>
		<cfset mappingDir = stMappings[arguments.mapping] >
		<!--- Go through the list backwards so that we get the longer partial matches listed first --->
		<cfset mappingKeys = ListSort(StructKeyList(stMappings),"text","desc") >
		<cfloop list="#mappingKeys#" index="thisKey">
			<cfif refindnocase(thisKey,mapping)>
				<cfset theEnd = replacenocase(mapping,thisKey,"")> <!--- get the extra bit from the mapping --->
				<cfset mappingDir = stMappings[thisKey]&theEnd > <!--- get the mapping directory and add the extra bit --->
				<cfbreak /><!--- Found what we need - lets stop --->
	<cfreturn mappingDir />
Its pretty simple and hopefully the comments are self explanetory. It pretty much goes through the list of mappings looking for the closest match and then appends the remainder to the end of the recorded path and returns that as the directory path.

Hopefully, my ramblings will make sense to someone and they will find this function useful.


Popular Posts