Extending Application.cfc's using mappings and proxies
Jan 30 |
This is a rather long article, if you want to jump to the condensed summary, scroll down to the bottom of this page. Many years ago, the first time that I tried to perform this, I received the following message no matter what I tried: "Could not find the ColdFusion component or interface xxx'. In a nutshell, the problem using this approach is that both the root and the subfolders have the same name, i.e. Application.cfc, and ColdFusion can't properly identify what component to extend. Finally, after some serious investigation, someone came up with the idea to create a proxy.cfc that resides in the same root directory as the root Application.cfc, and the Application.cfc in the subfolder extends an empty proxy.cfc that extends the root cfc like so:
root directory: Application.cfc
This root Application.cfc does not extend anything
Also in the root directory: Proxy.cfc
Proxy.cfc has the following code, its essentially empty. The only thing that the Proxy.cfc does is to extend the Application.cfc that is in the same directory:
<cfcomponent extends="Application">
</cfcomponent>
Subdirectory such as a folder named admin.
This subdirectory has another Application.cfc. Let's say that this component is responsible for securing the application and has login logic as well as debugging settings for example. This Application.cfc will extend the Proxy.cfc to gain the methods and properties of the Application.cfc in the root directory like so:
<cfcomponent displayname="Admin" extends="Proxy.cfc">
<!-- Lots of code --->
</cfcomponent>
This approach was a godsend and it was heavily blogged about. Ben Nadel has made a number of very helpful posts which I will share at the bottom of this article. This works quite well unless you're on a hosted domain or a server that uses virtual directories. In this case, we are in the same original boat in which we started from. Now we are back into the "Could not find the ColdFusion component or interface xxx' hell! There is a solution for this tricky problem though, we need to also use mapping! It is a common misnomer that you can't use mapping to extend components. I am not quite sure where this misconception originally came about, but it has been proven that this is just not true. There are occasions where we must use mapping to solve some annoying problems, like here. This particular site is hosted by hostek.com. They are a fine company to deal with, but the server that my site is hosted on has some idiosyncrasies due to the directory structure. Here, when I use the Proxy.cfc method to extend the logic from the base Application.cfc to the Application.cfc in the admin folder I receive the dreaded 'could not find the ... component' error. When I first saw it I was dismayed thinking not this again, so I turned to ColdFusion CFC mapping. Mapping tells ColdFusion where to find the file and what the file relationships are.
Let's review CFC structure that was just discussed. For example, imagine the following directory structure:
root directory: i.e. www.gregoryalexander.com/
subdirectory: www.gregoryalexander.com/admin/
As discussed, we have an Application.cfc and the Proxy.cfc in the root directory, and we have the Application.cfc in the 'admin' subdirectory. The Proxy.cfc extends the Application.cfc, also in the root directory, and the Application.cfc in the subdirectory (admin) extends the Proxy.cfc in the root directory. root directory: contains both Application.cfc and Proxy.cfc (that extends the root Application.cfc).
subdirectory: Application.cfc (that extends Proxy.cfc).
Now we need to also add the following mapping in the root Application.cfc. This mapping logic should be near the top of the root Application.cfc, and it should not be within any of the Application.cfc event handlers (onApplicationStart, onApplicationRequest, etc). This mapping code does not need to be anywhere else other than the root Application.cfc:
<!-- Define application-specific mappings. These will be used to point to this application.cfc when we extend it in the admin/Administrator.cfc template using the Proxy.cfc that resides in the same folder as this Application.cfc. --->
<cfset this.mappings="structNew()" />
<!-- Mapping for the ROOT Application.cfc --->
<cfset this.mappings["rootCfc"]="getDirectoryFromPath(getCurrentTemplatePath())" />
<!-- Mapping for the admin SUBDIRECTORY Application.cfc. Note the admin prefix is attached at the end of this line. This points to the admin folder. --->
<cfset this.mappings["adminCfc"]="getDirectoryFromPath(" getCurrentTemplatePath()="" &="" "="" admin"="" )="" />
I used rootCfc to identify the Application.cfc in the root directory, whereas adminCfc applies to the Application in the admin directory. These variables can be named anything. Note that the "/admin" string at the end of the adminCfc mapping points to the 'admin' folder, which is a subdirectory. Now that we have the mappings in the root Application.cfc, we need to apply them to the extends statement in Application.cfc located in the subdirectory. In the /admin/Application.cfc template use:
/admin/Application.cfc
<cfcomponent displayname="xxx" sessionmanagement="xx" clientmanagement="xx" extends="rootCfc.Proxy">
<!-- Logic --->
</cfcomponent>
Of course, rootCfc tells the Application.cfc in the subdirectory to look for the Proxy.cfc template in the root directory. Like other 'extend' statements, you don't need to specify '.cfc' at the end of Proxy. You don't need to use this 'extend' mapping in either the root Proxy.cfc or Application.cfc templates. They can already find each other as they are both in the same root directory. /Proxy.cfc
<cfcomponent extends="Application">
</cfcomponent>
Summary
For the sake of absolute clarity:
root Application.cfc
Contains the mapping logic. Has the mappings for both of the root and subdirectory.
This mapping logic should be near the top of the root Application.cfc, and it should not be within any of the Application.cfc event handlers (onApplicationStart, onApplicationRequest, etc).
Does not use an 'extend' statement
<cfset this.mappings="structNew()" />
<cfset this.mappings["rootCfc"]="getDirectoryFromPath(getCurrentTemplatePath())" />
<cfset this.mappings["adminCfc"]="getDirectoryFromPath(" getCurrentTemplatePath()="" &="" "="" admin"="" )="" />
root Proxy.cfm
A simple 'extends="Application" works.
No mapping logic.
<cfcomponent extends="Application">
</cfcomponent>
subdirectory Application.cfc
The extends statement must be the mapping variable name of the folder (rootCfc), a dot (.), and finally the name of the Proxy.cfc template without the .cfc prefix (Proxy)
No mapping logic.
<cfcomponent displayname="Admin" sessionmanagement="yes" clientmanagement="yes" extends="rootCfc.Proxy">
</cfcomponent>
My apologies for being so verbose. I annoyed myself while writing this- but not as annoyed when I was while trying to solve this problem! Take care! Related External Posts:
- Ben Nadel: Extending The Application.cfc ColdFusion Framework Component With A Relative-Path Proxy
- ColdFusion 8 Application Specific Mappings Work With The CFComponent Extends Attribute
- Ben Nadel: Extending The Application.cfc ColdFusion Framework Component With CFInclude
- Stack Overflow post by Edward M Smith
Tags
ColdFusionThis entry was posted on January 30, 2021 at 12:31 AM and has received 2327 views.