I have known for a while that you can use mixins to create dynamic functionality in a ColdFusion component, but for yucks, this morning I tried to CFInclude the entire ColdFusion component code (CFComponent tags and all) as a mixin. And, much to my surprise, it worked! Well, sort of. Here is the directory structure I am working with:
Notice that the last two files, BaseComponent.cfc and cfc_code.cfm, are in a separate, parallel directory (cfc_include2). In my index file, I am merely instantiating and using the Test.cfc ColdFusion component:
<!--- Create the Test ColdFusion component. ---> <cfset objTest = CreateObject( "component", "Test" ) /> <p> #objTest.Echo( "I'm bringing sexy back" )# </p>
Running this code, we get the following output:
I'm bringing sexy back
Ok, nothing interesting about that, until we look at how it is all coming together at run time. Let's look at the Test.cfc ColdFusion component:
<!--- Include the CFC code from another directory. ---> <cfinclude template="../cfc_include2/cfc_code.cfm" />
All that Test.cfc does is include a file from the parallel directory, cfc_include2. It doesn't even define CFComponent tags. It doesn't have anything but the CFInclude. Crazy stuff.
And, here is the cfc_code.cfm that is being included into the Test.cfc:
<cfcomponent extends="BaseComponent" output="false"> <cffunction name="Echo" access="public" returntype="any" output="false" hint="Echos back the argument that was passed in."> <!--- Define argument. ---> <cfargument name="Value" type="any" required="true" /> <!--- Return the value. ---> <cfreturn ARGUMENTS.Value /> </cffunction> </cfcomponent>
This ColdFusion template defines the ColdFusion component, including the CFComponent tags. As you can see, the Echo user defined function here is being access properly from the index.cfm file listed above. But, also, notice that the CFComponent tag for this template defines an EXTENDS component, BaseComponent. As you can see from the directory structure, BaseComponent.cfc is in the same directory as cfc_code.cfm, NOT in the same directory as Test.cfc.
Here is BaseComponent.cfc:
<cfcomponent output="false"> <!--- Give CFC instance a unique ID. ---> <cfset THIS.InstanceID = CreateUUID() /> </cfcomponent>
But, wait, there's more, if you CFDump out the Test.cfc instance, you get this output:
Notice that the Echo() method is defined in the THIS scope, but the InstanceID from the BaseComponent.cfc is NOT defined anywhere. Does this mean that it could NOT find the BaseComponent.cfc? No, if that were the case, ColdFusion would have thrown the following error:
Could not find the ColdFusion Component BaseComponent. Please check that the given name is correct and that the component exists.
However, NO error is being thrown. Yet, at the same time, it seems to be completely ignoring the Extends directive.
So, what does this all mean? I am not exactly sure. I am not even sure WHAT I would expect to happen. Frankly, I am surprised this worked at all. Here's what we know:
- The entire content of a CFC can be included at runtime (include CFComponent tags).
- The included CFC cannot seem to Extend another CFC.
- Extends attribute does not work, but does NOT throw an error.
I don't think I would EVER use anything like this, but I think the idea of creating "Shell" CFCs for a centralized repository for actual CFC code is vaguely interesting. Anyone have any thoughts on this?
I thought maybe the name, BaseComponent, was a special name, but it didn't matter. If I changed the CFC name I kept getting the same outcome. I was also surprised by the CFDump output label, "component WEB-INF.cftags.component". This is NOT where the Test.cfc is located. Something VERY STRANGE is going on here :)
Want to use code from this post? Check out the license.