ColdFusion 8 Application Mappings and Sub-folders
2008 February 27
Now that I'm on a CF8 hosting plan, I've started leveraging some of that goodness in my applications. The first thing I have implemented is application level mappings to keep my configuration files and components out of the web root. Here's how my current project layout rolls.
/project /config <-- Coldspring and Transfer config files /model <-- model components /root <-- web root /admin <-- secure admin screensBasically, I want to create mappings to config and model. I did a little googlin' and found a nice snippet on Sean Corfield's blog on looping over a list to build the mappings. I aped that code with a slight mod for my setup.
<cfif (ListLast(CGI.HTTP_HOST,".") eq "local")>
<cfset mapPath = "../">
<cfelse>
<cfset mapPath = "../" & this.name & "/">
</cfif>
<cfloop index="p" list="config,model">
<cfset this.mappings["/" & p] = expandPath(mapPath) & p />
</cfloop>
I dev on Mac and deploy on Windows and my local folder structure is slightly different from my host. The first part of the code is just a test of whether the site is being served up locally. When on the production server, the mapped folders are in a folder with the same name as the app.
This is a great alternative to using Apache Alias or Virtual Directories in IIS for mappings. That is, until I tried using the mapping from within the admin folder. Suddenly the path was not recognized. I initially thought this was a transfer issue, but that was not the case. I tried several variations and workarounds. Eventually, I figured out that the mappings were fine for files in the web root where Application.cfc resides. So why was the path not available to files in a folder below the web root? The answer was pretty simple. The admin folder had no Application.cfc, thus no mappings.
Remembering another gem by Mr. Corfield regarding extending Application.cfc via a Proxy, I created an Application.cfc in the admin folder and the required proxy in the web root. Instead of repeating the code for creating the mappings with only the path prefix changed, I wrapped the creation of mappings up in a method.
<cffunction name="createMappings" access="private" output="false" returntype="void">
<cfargument name="pathPrefix" type="string" required="false" default="../">
<cfif (ListLast(CGI.HTTP_HOST,".") eq "local")>
<cfset variables.mapPath = arguments.pathPrefix>
<cfelse>
<cfset variables.mapPath = arguments.pathPrefix & this.name & "/">
</cfif>
<cfloop index="p" list="config,model">
<cfset this.mappings["/" & p] = expandPath(variables.mapPath) & p />
</cfloop>
</cffunction>
And call it from the Application.cfc in the admin folder using the appropriate prefix.
<cfcomponent displayname="Application" extends="ApplicationProxy">
<!--- set mappings in this directory --->
<cfset createMappings(pathPrefix="../../")>
</cfcomponent>
Application level mappings are handy, but the per directory limitation does not make for a tad more code. Overall, I think it's a small price to pay for the benefit gained.
UPDATE:
After testing this on my Windows machine, it appears that using "this.mappings" inside a method does not properly set the mappings. I've changed things around so that the createMappings() method returns a struct and I set it as a pseudo-constructor.<cfset this.mappings = createMappings(pathPrefix="../") >