ColdFusion Component MetaData

I recently needed to get the list of functions from a component that I was building. This is helpful especially if you want to loop through the list of functions and execute all of them. Now, this is possible by listing the functions in a variable in a component, but that's not very scalable because every time I add or remove a function, I have to subsequently add or remove that function from the list. So, here is how you dynamically get the list of functions from a component:

<!--- Instantiate the component. CMS --->
<cfset obj = CreateObject("component","com.test.ExpressComponent") />

<!--- Get the metadata. CMS --->
<cfset md = getMetaData(obj) />

<!--- Now loop through the variables. CMS --->
<cfset mdfunc = md.functions />

<!--- Here I dump the info. But it can be processed in whatever manner. CMS --->
<cfloop from="1" to="#ArrayLen(mdfunc)#" index="k">
   <p><cfdump var="#mdfunc[k]#" /></p>
</cfloop>

The getMetaData() function returns a nicely formatted structure of various information about the component. Here is a dump of it:

cfdump of getMetaData() result.

Lot's of valuable information about the component.

Benefits of Unit Testing

The following are some benefits to ColdFusion unit testing that I've noticed while creating them over the past several days:

  • As I write the unit tests (and the subsequent code for the cfcs) I find that changes are actually quite simple. It makes it easier to make changes in the beginning. IMHO, it is much more difficult to make changes as I'm implementing the CFC into the presentation layer.
  • As I develop unit tests, I establish the expected behavior of the CFC even before I begin to create it. This allows me to have a more absolute concept of what the CFC is supposed to do early on. As mentioned above, that's much easier to change than if the whole darn CFC is already coded and implemented in an interface.
  • Initial bugs are found and fixed before connecting to the interface. I have a fully functional CFC that has been bug tested (by the unit testing) prior to its implementation. Plus, I'm not bug testing with the interface (except for interface bugs) because that's already been done with the unit test. So nice.

I'm sure there are so many other reasons to do unit tests that I haven't covered. If I think of any, I'll post them. Otherwise, feel free to post your reasons for unit testing.

Which ColdFusion Unit Testing Framework?

I'm currently using MXUnit. In the past I've tried CFUnit which was really nice, BUT THEY STOPPED UPDATING IT! It's been dormant for about 18 months.

I've also tried CFCUnit but they stopped updating it over two years ago! That's a bummer because their interface was really nice.

MXUnit is currently being updated, supported and they even have an Eclipse plug-in (that I haven't tried yet). They have an active blog and an active Google Group to get support.

New Team Collaboration Tool...

Today we released our team collaboration tool at MondoTeams.com. It is a free online tool that allows you to:

  • Create and manage projects
  • Invite team members to join your project and participate in the project development.
  • Create deadlines, bulletins, and comments on the project.
  • Create tasks to be done on the project.
  • Track your time spent on projects.
  • Build time reports for customer invoices on time spent on projects.
  • Create folders for the project and upload files to those files.
  • Track file revisions.
  • Project calendar tool.

It's all written in CF and AJAX and is free for you to use! There are obvious limitations, like a maximum number of projects (20), folders and files (I'll have to look that up), etc. However, the limitations are generous and should be plenty for most projects.

We are also creating some new and improved features that I'll blog about in the future.

Also, another tool we created is call MondoDesigner.com. This tool allows you to create your own web sites (for those who don't want to get into code), host it on our servers, add a blog, and community sign in, and use your same login and password for all of the Mondo tools.

We have a whole suite of tools and projects that we'll be releasing in the future. I'm way excited about them and I'll keep you posted!

Using cflogin Properly

So, I've just been implementing cflogin on one of my web sites. With 5+ years experience in ColdFusion this may seem odd, but, in my defense, my team implemented a little more comprehensive security and authentication system which did not use cflogin.

Thus, I had a hard time finding a problem with my cflogin code, which is in my Application.cfc:

<cfset var qrylogin = "" />

   <cflogin>
      <cfif IsDefined("form.username")>
         <cfquery name="qrylogin" datasource="#application.dsn#">
            SELECT * FROM lwm_user
               WHERE username = <cfqueryparam value="#form.username#" cfsqltype="cf_sql_varchar" />
                  AND password = <cfqueryparam value="#Hash(form.password)#" cfsqltype="cf_sql_varchar" />;
         </cfquery>
         
         <cfif qrylogin.RecordCount EQ 1>
            <cfloginuser name="#form.username#" password="#form.password#" roles="#qrylogin.role_list#" />
            <cflocation url="#cgi.http_referer#" addtoken="false" />         
         </cfif>
      </cfif>
      

         <cfinclude template="/CStores/content/includes/login.cfm" />
         <cfoutput>#getSimpleFooter()#</cfoutput><cfabort>

   </cflogin>

I quickly found that this code would not work properly. I was expecting to use getAuthUser() and isUserLoggedIn() but found they contained [empty string] values.

I began to search beyond my bubble and looked into Ray Camden's Lighthouse code and found the solution:

<cfset var qrylogin = "" />
   <cfset var showLogin = true />
   
   <!--- Check to see if they are logged in. CMS --->
   <cflogin>
      <cfif IsDefined("form.username")>
         <cfquery name="qrylogin" datasource="#application.dsn#">
            SELECT * FROM lwm_user
               WHERE username = <cfqueryparam value="#form.username#" cfsqltype="cf_sql_varchar" />
                  AND password = <cfqueryparam value="#Hash(form.password)#" cfsqltype="cf_sql_varchar" />;
         </cfquery>
         
         <cfif qrylogin.RecordCount EQ 1>
            <cfloginuser name="#form.username#" password="#form.password#" roles="#qrylogin.role_list#" />
            <cfset showLogin = false />
         </cfif>
      </cfif>
      
      <cfif showLogin>
         <cfinclude template="/CStores/content/includes/login.cfm" />
         <cfoutput>#getSimpleFooter()#</cfoutput><cfabort>
      </cfif>
   </cflogin>
   
   <cfinclude template="#arguments.targetPage#">

The difference is I got rid of the cflocation after validation and added the showLogin variable to include the login form if needed. This worked perfectly. Some thoughts:

1) I'm assuming that the </cflogin> tag needs to be completely parsed in order for the login to complete. Because I relocated before the </cflogin>, nothing was happening.

2) While placing the login code and query in the Application.cfc is convenient, I'm not sure if this is the proper place for it. I guess, I could move it into a component which just makes it a little more modular. However, this location is great especially for this application where authentication is required anywhere in the system. Need to figure out a way to implement it in only certain places of the site.

3) I'm thinking we could have used this in my previous project. It's so easy to implement. But why make it easy when you can do it yourself?! Duh.

Referencing XML Attributes in ColdFusion

I was having a little problem with referencing some XML attributes in a ColdFusion XML object. Essentially, I couldn't reference them even though they were defined. My original code was:

<cfloop from="1" to="#ArrayLen(xmlObj.XmlRoot.XmlChildren)#" index="r">
<cfset elemAtt = xmlObej.XmlRoot.XmlChildren[r].xmlAttributes />
<cfset attName = elemAtt.name />
....
</cfloop>

When processing, ColdFusion kept returning "variable 'name' is not defined in elemAtt." So I proceeded to insert dumps, isdefineds, etc. to verify that it was there; and it was! So, after 20 or 30 minutes of working on this, it came to mind to copy the struct and then reference it. Like this:

<cfloop from="1" to="#ArrayLen(xmlObj.XmlRoot.XmlChildren)#" index="r">
<cfset elem = Duplicate(xmlObj.XmlRoot.XmlChildren[r].xmlAttributes) />
<cfset attName = elemAtt.name />
....
</cfloop>

This worked perfectly. Not sure why I couldn't reference it without the duplicate. It obviously had something to do with the attributes within the XML Object not really being a struct. But using the duplicate function, it copies the attribute struct as a struct (if that makes sense) and then it can be referenced normally.

I'll have to investigate the reasoning later.

Follow-up: ColdFusion System Properties...

In my blog post about ColdFusion System Properties I explain a way to gather information about your server using the java.lang.System classes. Well, after a little hunting you can grab most of this information easier by using the ColdFusion server variables. For example, dumping the server.coldfusion variable returns the following structure:

server.coldfusion variables

And the server.os variable returns this structure:

server.os variables.

Just what I needed and I didn't have to use Java. Which is faster and less lines of code.

Securing HTML Forms

I'll admit that I sometimes use hidden form fields in my web applications. I cringe every time I do, but I do it anyway. They're convenient and make it easy to track some elements in a web application.

The problem with hidden form fields is that users can manipulate them. This is done by simply saving the web page to disk, modifying the code, then opening the page on disk in a web browser and submitting the form. This is dangerous and can cause severe problems. Hence, securing forms is essential. This is how I do it:

[More]

ColdFusion Cfencode and Cfcompile Utilities

ColdFusion has two utilities that are available to obfuscate code. This is useful when you don't want users to see or modify your plain text CFML code. However, there are some drawbacks to both utilities...

[More]

ColdFusion System Properties...

I recently needed to use ColdFusion to determine some properties of the operating system. This is easily done with the following code:

<cfset sysObj = CreateObject("java","java.lang.System") />
<cfset tmpOSProps = sysObj.getProperty("os.name") />

The getProperty() method is used to access several of the system properties. The parameter sent is the key to the property you want to access. A list of keys can be found on Sun's web site.

It should be noted that if you are in a shared hosting environment, you may not be able to use the CreateObject() method. Thus, you will not be able to access the java objects.

Array Notation vs. Evaluate()

While developing a web site for a customer, I recently had the problem with evaluating a form field to retrieve that field's value. For example:

I had a form field as follows:

<input type="text" name="q_1_f35d5381-c9f7-431e-6332-4d404f55ed4c" id="q_1_f35d5381-c9f7-431e-6332-4d404f55ed4c" size="25" value="" />

As you can see I'm using a GUID in the name. This helps me map the form back to another entity after processing.

In order for me to get the value of the field, I loop through the fieldnames and Evaluate() that field as follows:

<cfloop list="#frm.fieldnames#" index="x">
<cfset s.value = Evaluate("frm.#x#") />
</cfloop>

However, when I submit the form and run the code, I received this CF error:

"4d404f55ed4c," on line 1, column 33, is not a valid identifer name.
The CFML compiler was processing: an expression beginning with "frm.q_1_f35d5381", on line 1, column 1.This message is usually caused by a problem in the expressions structure.

It looks like CF attempts to "subtract" the values between the "-" in the GUID. In other words, its attempting to subtract 4d404f55ed4c from 6332 which are the values at the end of my GUID.

After a few hours of attempting to resolve this issue I finally posted the issue on the Adobe Forums.

After just a half-hour a kind fellow by the name of Azadi (thanks Azadi, whoever you are) provided a fantastic solution: Array notation on the structure iteself instead of using evaluate! Duh.

I've used this solution before but not on a form structure. So, I changed the code that proceses the form as follows:

<cfloop list="#frm.fieldnames#" index="x">
<cfif StructKeyExists(frm,"#x#")>
<cfset s.value = form['#x#'] />
</cfif>
</cfloop>

And it worked beautifully. Remember array notation instead of Evaluate() is a good option in this circumstance.

More Entries

Contact Chris SchofieldBlogCFC was created by Raymond Camden. This blog is running version 5.9.001.