I'm working on a proof of concept ColdFusion Builder Extension for work and it requires that I examine a CFC. That should be easy enough, right? We have the getComponentMetadata function which returns a nice structure of information about the CFC. However, there is one problem with this function. All CFC functions in ColdFusion require a "dot path". Unless the CFC is in the same folder you need to use a "dot path" location to tell ColdFusion how to load the CFC. Since this CFBuilder extension has to work with any CFC on the file system, it isn't really practical to figure out how to get path to that CFC. What follows is one solution to this issue - I'm not terribly happy with it but it seems to work.
To begin my CFBuilder extension, I created my ide_config.xml file. I won't go into full details about each line here - check the CFBuilder docs for a full explanation on how to build extensions.
<menucontributions>
<contribution target="projectview">
<menu name="Get CFC Metadata">
<filters>
<filter type="file" pattern=".+.cfc" />
</filters>
<action name="Do It" handlerid="getcfcmeta" showResponse="no" />
</menu>
</contribution>
</menucontributions> <handlers>
<handler id="getcfcmeta" type="cfm" filename="getcfcmeta.cfm" />
</handlers>
</application>
<application>
<name>CFC Test</name>
<author>Raymond Camden</author>
<version>1.0</version>
<email>ray@camdenfamily.com</email>
<description>Attempts to get metadata for a CFC.</description>
<license>Just Use It.</license>
There are two things I want to point out here. First - notice how I used a pattern on the menu. Thanks to Dan Vega for helping me realize that the value for pattern is a regex. I began with *.cfc which didn't work correctly. Secondly make note of getcfcmeta.cfm. That's the file that will contain the main code to handle my solution. Let's take a look at that next.
<cfset newName = replace(createUUID(), "-", "_", "all")>
<cfset newLocation = getDirectoryFromPath(getCurrentTemplatePath()) & newName & ".cfc"> <!--- Copy the file --->
<cffile action="copy" source="#myFile#" destination="#newLocation#"> <cfset meta = getComponentMetaData("#newName#")> <cfdump var="#meta#" output="c:\webroot\test.html" format="html"> <cffile action="delete" file="#newLocation#">
<cflog file="bolt" text="I'm done. Stored to #newlocation#">
<cfparam name="ideeventinfo">
<cfset data = xmlParse(ideeventinfo)>
<cfset myFile = data.event.ide.projectview.resource.xmlAttributes.path>
<cflog file="bolt" text="Working with #myFile#">
So we begin by parsing out the XML sent to the extension. This is all documented but while I was developing I made copious use of cflog to look at the XML. Just know that the myFile variable will contian the full path to the CFC that was selected in the Navigator.
Now it's time for the hack. I decided I'd simply copy the CFC to the same folder as the extension. I used a new name based on UUID. Once copied I was able to use getComponentMetaData. Note that newName is just the UUID, it doesn't include the path or the extension. Once I had it I confirmed it by using cfdump. (Don't forget ColdFusion 8 added the ability to dump to a file. It's useful for situations like this where I'm working with extensions.) Finally I delete the file.
That's it. So does it work? Yes and no. It does correctly reflect function metadata which for my case is all I need. However some values, specifically fullname, name, and path, reflect the temporary copy of the CFC. Here is an example:
Archived Comments
I would think that the incorrect value for path would be easy to current. Name and fullname would, of course, be another matter (though I suppose you could just have the extension remove those from its output).
I would think that a bigger issue would be component extension. If the component is extending another component then it might not be found from the CFC in its new (copied) location.
Good point on the inheritance. I'll try that in a few - I bet it will fail miserably.
I have never worked with extensions before so I apologize if this is off base but could you get the Path Etc from this: <cfset myFile = data.event.ide.projectview.resource.xmlAttributes.path>
For the name I was thinking you could use the path and replace the slashes and remove the .cfc on the actual file name but there would be the issue of figuring out what the webroot is and removing it from the name.
and then add that update /add the info to your Meta Struct?
Randy, you can't use the path to get metadata for a CFC. You must use "dot" notation which is based on either the current folder, or CF mappings (or custom tag paths as well). For the name though - you are right. That would work.
Hey Ray -= check out my cfpropertyinspector on riaforge - I'm doing this here
http://cfpropertyextension....
Checkout CFC2UML (CFB Extension) cfc2uml.riaforge.org.
Method "AbsoluteToDotPath" in CFC2UML.cfc.
There you'll see how to translate physical path to dot-delimited format, taking internal app mappings in consideration. There are 2 solutions depending of server type: Adobe CF or Railo 3.x. If anyone know how to do it on OBD I'll be glad to implement support for that server too.
@Kevin - I downloaded your project - but can you tell me what part of the code handles the issue this blog entry covers - specifically getting component metadata from a random path?
@Ray -
Well it might be a bit different in that I'm asking for a mapping (optional) and path from the user - which allows me to make the appropriate guess as to the path - another alternative I thought of but didn't implement is to use the mappings list from cfadmin, but I'd have to ask for server credentials and figured that would be a bit too intrusive. A search for 'getComponentMetaData' will likely pull it.
@ray - you can add an alias to all your CFC's which has the full qualified dot-notation path.
I'm working on a project where I need to put that in for Flex, to consume CF services.
That way your MetaData extension will always have what you need in the "Alias" property.
Just a thought.
--Ali
Sorry - an Alias? What do you mean?
@ray -
I mean, if you have a cfc called myTest.cfc
and it's in a folder called extensions/cfctest/handlers
In the component declaration using cfscript syntax you could say:
component alias="extensions.cfctest.handlers.myTest" displayname="test it ray"
{
// methods go in here
}
That way in your metadata you'll always get the dot path whenever you introspected it.
--Ali
Ok sorry Ray, alias is only used if the CFC in question is going to be converted to an AS3 object for Flex or LiveCycle.
It doesn't really apply, then in this situation, I guess......