ColdFusion 8 Application Mappings and Sub-folders
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 screens
Basically, 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.
<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.
<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.
<!--- 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.



It seems that there is something else wrong. I have to wonder if it has to do with your relative paths as I've not done that before. My mappings are all in the way of
C:\var\wwwroot\site1\ or some such thing.
See any code set above a function in a component will run each time and your relative pathing may make it so that calling it from a subfolder is making the mapping relative to the subfolder. So, the subfolder is processing the top level application.cfc from it's location, not the application.cfc location
Using expandPath() sets a full file system path. On my Mac that resolves as /Users/paul/htdocs/project/. Believe me, I dumped the mappings and tried several variations. Before I put Application.cfc in the sub-folder, the paths were not recognized. I may be wrong on this,. It's been known to happen. ;)