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.
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.
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).
As mentioned before, much of this information is standard knowledge. But standard isn't fun, so let's get to the tests.
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.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:/cfusionmx/wwwroot/ |
Table 1.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 Figure 1.1 as a guide, create the folders on your system.
C: +--- cfusionmx7 | +--- CustomTags | | +--- map_test | +--- wwwroot | +--- map_test +--- data | +--- www | +--- map_test +--- map_test
Figure 1.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 Figures 1.2 and 1.3, create the index and first include page we'll use throughout our testing.
Figure 1.2 - C:/data/www/map_test/index.cfm
Figure 1.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 Figure 1.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.
Figure 1.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 Figure 1.5 below as a guide. This will test the ColdFusion web server root.
Figure 1.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 Figure 1.6 below.
Figure 1.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.
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.
The following tables reveal the basic results of testing all the ColdFusion features outlined in Keeping Code Modular. Table 1.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 | Precedence | '/' Notation | '\' Notation | '.' Notation | Mix Notation |
| cfinclude |
|
Yes | Yes | No | Yes, even trailing slashes of both types. |
| cfmodule (using the name attribute) |
|
Yes | No | Yes | Yes, but no trailing '/' or '.' |
| cfmodule (using the template attribute) |
|
Yes | Yes | No | Yes, even trailing slashes of both types. |
| <cf_[some_tag]> |
|
n/a | n/a | n/a | n/a |
| cfinvoke |
|
Yes | Yes | Yes | Yes, but no leading '.' and no trailing '\', '/', or '.' |
| cfobject |
|
Yes | Yes | Yes | Yes, but no leading '.' and no trailing '\', '/', or '.' |
| createObject |
|
Yes | Yes | Yes | Yes, but no leading '.' and no trailing '\', '/', or '.' |
| cferror |
|
Yes | Yes | No | Yes |
Table 1.2 - Final Results
While performing the tests for this writing, curiosity set in which revealed the following points:
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.
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.
This applies in particular to consultants and other internal development staff that may move from project to project.
The recommended directory depth when this option might be considered is four.
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.
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.
I hope 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.