Truths: ColdFusion Mappings

April 27, 2007

by Brice Mason

Home » Articles

There is a feature of ColdFusion with the ability to help you be more productive, develop code consistently across all environments, and even offer some extra security for your source code. While I'm sure you can come up with at least ten features immediately in your head, I'd be willing to bet you didn't guess ColdFusion mappings as one of them. Mappings are a simple yet powerful feature of ColdFusion. Their purpose and behavior deserves a little more attention than most developers would normally give it, we'll show you why.

To be honest, this writing isn't completely about ColdFusion mappings. Rather, it's about mapping's role in the way we link modular code into our pages. Through numerous tests, we can confirm among other things that a hierarchy exists which manages the inclusion of modular code into our pages.

Keeping Code Modular

ColdFusion provides us a rich set of features dedicated to the modular maintenance of source code. For the purposes of this writing, we'll focus on the following tags and functions that promote this capability.

  • <cfinclude />
  • <cfmodule />
  • <cf_[some_tag] />
  • <cfinvoke />
  • <cfobject />
  • createObject()
  • <cferror />
  • UDFs through the use of <cfinclude />

By studying the documentation provided on these tags and functions, you'll be able to create working, stable code. However, with a little extra curiosity and patience, you'll be able to discover some interesting behaviors of ColdFusion that you won't find documented anywhere else. In order to test these behaviors, we'll use the following resource locator paths. These paths were chosen because they can be referenced just like mappings (root relative style).

  • Root relative linking ( /first_sub_folder/some_file.cfm )
  • Custom tags directory ( c:/cfusionmx7/CustomTags/ )
  • ColdFusion default web root ( c:/cfusionmx7/wwwroot/ )
  • Mappings ( /mapping_root/some_folder )

As mentioned before, much of this information is standard knowledge. But standard isn't fun, so let's get to the tests.

The Test

For brevity sake, we'll be walking through the test of just the cfinclude tag. Later on, the results of all the other tags and functions mentioned in the previous section will be available. These tests were performed in an environment as shown in Table 1 below.

Test Environment
OS: Windows XP Professional SP2
Web Server: IIS 5.1
Web Root: C:/data/www/
ColdFusion Version: 7.02
ColdFusion Configuration: Server
ColdFusion Installation Directory: c:/cfusionmx7
ColdFusion Custom Tags Directory: c:/cfusionmx7/CustomTags
ColdFusion Default Web Root: c:/cfusionmx7/wwwroot

Table 1 - Test Environment

First we'll need to create a couple of folders that will accommodate all the places we want to store the include files for testing. Using Listing 1 as a guide, create the folders on your system.

C:
+--- cfusionmx7
|      +--- CustomTags
|      |      +--- map_test
|      +--- wwwroot
|             +--- map_test
+--- data
|      +--- www
|            +--- map_test
+--- map_test

Listing 1 - Base Directory Structure

As you can see, we are creating a system of overlapping folder names in the four key folders mentioned in the previous section. Now, using Listings 2 and 3, create the index and first include page we'll use throughout our testing.

<html>  
<head>  
    <title>cfinclude Testing</title>  
</head>  
<body>  
    <h3>cfinclude Testing</h3>  
    <cfinclude template="/map_test/cfinclude_test.cfm" />  
</body>  
</html> 

Listing 2 - C:/data/www/map_test/index.cfm

cfinclude - root relative  

Listing 3 - C:/data/www/map_test/cfinclude_test.cfm

Now, if we serve up the index page we should see the following:

This looks just fine so let's move on to the next level. Create another include file according to Listing 4 below and move the include file from C:/data/www/map_test/ to an offline location. Now test to ensure the custom tags folder does not factor in to ColdFusion's search path for cfincludes.

cfinclude custom tags folder

Listing 4 - C:/cfusionmx7/CustomTags/map_test/cfinclude_test.cfm

Giving the index page a refresh, you should see the following:

Just as we would suspect, the CustomTags folder does not have an impact on the search list for cfincludes. Restore the offline include file to its original location (C:/data/www/map_test/) and create a new include using Listing 5 below as a guide. This will test the ColdFusion web server root.

cfinclude ColdFusion default web root

Listing 5 - C:/cfusionmx7/wwwroot/map_test/cfinclude_test.cfm

Refresh the index page again. You should get the following result:

Not only does this work, but it overrides a root relative path. While this does seem surprising especially when running under an IIS web site, there are some other peculiar behaviors to explore in the More Oddities section below.

Now we'll give a final test on a ColdFusion mapping itself. In the ColdFusion Administrator, create a mapping with the logical path of /map_test and the physical path C:/map_test, then save the final include file as outlined in Listing 6 below.

cfinclude mapping

Listing 6 - C:/map_test/cfinclude_test.cfm

Refresh the index page again to reveal the following:

This demonstrates that the mapping overrides all other cases. This can be a fairly important concept when we have templates of the same name, one intending to be referred to in a root relative path, and the other a mapping. This could happen when migrating code from differing environments that weren't planned accordingly or even when developing debugging code in a development environment. If you don't understand the precedence ColdFusion takes when processing these includes, you could be left scratching your head.

On Notation

What hasn't been included in this simple walkthrough are some additional tests which involves notation. For example, we know we are able to use at least two types of notation when referring to assets in say, cfinclude and cfinvoke. The first is a standard path notation such as /some_folder/some_file.cfm while the other is package notation some_path.to.a.component. As you'll see, ColdFusion will accept not only these standard notations we're all used to, but also backslashes and even a mix of all three at once.

Final Results

The following tables reveal the basic results of testing all the ColdFusion features outlined in Keeping Code Modular. Table 2 reveals the precendence that ColdFusion implements as well as the accepted notation for each mechanism. The precendence is listed from highest to lowest.

Final Results
Mechanism Precendence '/' Notation '\' Notation '.' Notation Mix Notation
cfinclude
  1. Mappings
  2. ColdFusion web root
  3. Root relative
Yes Yes No Yes, even trailing slashes of both types.
cfmodule (using the name attribute)
  1. Custom tags folder
Yes No Yes Yes, but no trailing '/' or '.'
cfmodule (using the template attribute)
  1. Mapppings
  2. ColdFusion web root
  3. Root relative
Yes Yes No Yes, even trailing slashes of both types.
<cf_[some_tag] />
  1. Root relative
  2. Custom tags path
n/a n/a n/a n/a
cfinvoke
  1. Mappings
  2. ColdFusion web root
  3. Custom tags path
  4. Root relative
Yes Yes Yes Yes, but no leading '.' and no trailing '\', '/', or '.'
cfobject
  1. Mappings
  2. ColdFusion web root
  3. Custom tags path
  4. Root relative
Yes Yes Yes Yes, but no leading '.' and no trailing '\', '/', or '.'
createObject
  1. Mappings
  2. ColdFusion web root
  3. Custom tags path
  4. Root relative
Yes Yes Yes Yes, but no leading '.' and no trailing '\', '/', or '.'
cferror
  1. Root relative
Yes Yes No Yes

Table 2 - Final Results

More Oddities

While performing the tests for this writing, curiosity set in which revealed the following points:

  • For the tags and functions that include the default ColdFusion web root, when this resource is picked up from this location, ColdFusion will get stuck thinking it should still find the asset there. The only way to release this is to restart the ColdFusion service.
  • The Mappings page in the ColdFusion Administrator will accept invalid physical paths. Really, the only situation it validates is an empty value. The Administrator also does not check to ensure that the physical directory exists. This can be a problem for configurations where RDS is disabled and you need to manually enter in physical paths.
  • In situations where the physical directory of a mapping is incorrect, ColdFusion will throw an error, even when a 'backup' file exists in say a root relative path. It is not intelligent enough to move to the next option.

Best Practices

There are many situations where you could find yourself in an environment with overlapping resources as described above. What you'll really want to take away from this writing is a set of best practices geared towards using mappings the right way.

  1. Use mappings to create consistent code across all environments
  2. This will usually require some planning. Suppose we have a production environment for a corporate intranet hosted on a server with the root folder of /marketing. Usually your development environment would be on a client machine which might have a restriction of one web site, forcing you to use virtual directories. Your development machine's root folder in this case might be /www/marketing. We could create a mapping in both environments with the logical path of /intranet_mkt. For larger environments, it is recommended that formal development policies be drafted to govern this process.

  3. Use mappings when you need to adapt to differing environments
  4. This applies in particular to consultants and other internal development staff that may move from project to project.

  5. Use mappings to cut down on directory structure length.
  6. The recommended directory depth when this option might be considered is four.

  7. Use mappings to offer an added layer of security to modular code.
  8. There are situations when the modular code that we maintain should never be directly requested by the user. In these cases, this code should be stored in an offline directory and made available to us as a ColdFusion mapping.

  9. Problems aren't always visible straight away
  10. Be careful, just because your code evaluates correctly at first glance, there are times when you might conditionally link in modular assets to your source code. Until either you inspect your code carefully or the condition arises in your code, you won't know the bug is there.

Hopefully you have survived all the way to the end of this writing with an appreciation of how complex and important the basic idea of a ColdFusion mapping can be.

Resources