This blog post is a bit silly because it's merely confirming something that was supposed to work. However, until last night, for some reason, I was under the impression that application-specific mappings in ColdFusion 8 did not work the CFComponent Extends attribute. This wasn't just some wild theory I had - I thought this because I've had a number of problems getting application-specific mappings to work in applications ported from CF7 to CF8 in which frameworks such as ColdSpring were used; even after settings up "ColdSpring" as an application specific mapping, the framework still threw errors about components that it couldn't find.
Last night, I asked about changes to this in ColdFusion 9, and both Ben Forta and Adam Lehman put me straight - it's supposed to work with application-specific mappings in CF8. So, this morning, I put together a small demo to see if I was crazy. I constructed the following directory tree:
As you can see, the "com" directory is parallel to my "app" directory so, in order to create a CFC in the app, I'm going to need a mapping. But then, the Test.cfc is going to extend the Base.cfc using a mapping as well. Here is my Application.cfc with mapping:
<cfcomponent output="false" hint="I provide application level settings and event handlers."> <!--- Defnie request settings. ---> <cfsetting showdebugoutput="false" /> <!--- Define application-specific mappings. ---> <cfset THIS.Mappings[ "/com" ] = ( REReplace( GetDirectoryFromPath( GetCurrentTemplatePath() ), "[^\\/]+[\\/]$", "", "one" ) & "com\" ) /> </cfcomponent>
As you can see, I am creating a mapping, "/com", by moving up one directory from the current directory and then appending "com\" to the end.
In my "com" directory, the Test.cfc extends the Base.cfc, so let's look at the Base.cfc first:
<cfcomponent output="false" hint="I am the base component for this package."> <cffunction name="Test" access="public" returntype="string" output="false"> <cfreturn "I am com.Base.Test()" /> </cffunction> </cfcomponent>
As you can see, not much going on. The Test() method simply returns a string containing the mapped method that was executed. Now, let's take a look at the Test.cfc that extends the Base. Notice that the Extends attribute of the CFComponent tag uses the application-specific mapping defined in our Application.cfc:
<cfcomponent extends="com.Base" output="false"> <cffunction name="Test" access="public" returntype="string" output="false"> <!--- Return test string from both the super component (from extends attribute) and the current component. ---> <cfreturn ( "[ #SUPER.Test()# ] " & "I am com.Test.Test()" ) /> </cffunction> </cfcomponent>
Ok, so now that we have all of our components in place, let's take a look at the code that ties it all together - the index.cfm page. My Index.cfm page simply creates the Test.cfc component using the application-specific mapping and calls its Test() method:
<!--- Create an object with the mapping. ---> <cfset objTest = CreateObject( "component", "com.Test" ) /> <!--- Test component method.. ---> <cfoutput> #objTest.Test()# </cfoutput>
When we run this code, we get the following output:
[ I am com.Base.Test() ] I am com.Test.Test()
As you can see, not only did the application-specific mapping let me create the Test.cfc component, it also allowed the Test.cfc component to extend the mapped Base.cfc component.
Like I said before, this is the expected behavior! Looking at it now, it seems so simple; I am not sure what problems I could have possibly been having with this before, but clearly it was an error on my part. There's nothing more frustrating than when silly mistakes cost you time and energy.
Want to use code from this post? Check out the license.