Showing posts with label components. Show all posts
Showing posts with label components. Show all posts

Thursday, June 12, 2008

Overlooked Techniques

We're all creatures of habit, and forming good ones is key to a long and productive career. I want to post at least a few of my favorite techniques that I believe are 'highly' overlooked in almost every application I look at/code I review.

1.) ColdFusion HTMLEDITFORMAT on HTML form field values

First off, let me give an example of what can happen if you don't use HTMLEDITFORMAT on your data that is either redisplayed from the user, or directly from a database.

Example:
<input type="text" value=""/>I am now Writing directly to this page and can do whatever I want, including relocate a person to another website using javascript etc. "/>


Trusting user input is not only unsafe but can lead to strange formatting issues when someone has quotation marks in their text (and you are using quotation marks in your html input attributes)
Rule of thumb - always use it to Wrap all cfusion dynamic data in html inputs
i.e.
<input type="text" value="#htmleditformat(variables.dbData)#"/>


2.) ColdFusion 'output=false' on cfcomponent tag and all cffunction tags within a component

Trying to debug this issue can be a nightmare, so just always set
output=false
Your cfcomponent and cffunction tags both have the 'output' attribute and should be set to 'false' if you're not returning data to the page (which you should limit the display from cfc method anyway)
.
If you're like us and use Eclipse/cfeclipse, then have this in your snippet for the creation of functions, and you will never have to try and hunt down a single space issue in your application again.

3.) JavaScript escape() function for url data

When you append data to the url in a javascript string, the characters you are appending need to be url safe. The escape() function does exactly this.
Example:

document.location.href="index.cfm?page=x.y&firstname=" + escape(x)


Special characters and spaces etc will need special treatment and not unlike the urlencodedformat() in coldfusion, javascript data needs to be treated with the same respect through the url.


Tuesday, June 10, 2008

Comparing two ColdFusion Objects (object comparison)

The problem I am trying to figure out is if there was a great way in ColdFusion 8 to compare 2 objects just like you would compare 2 strings using a 'Compare' function
For example:
Compare(string1,string2)


I found no such function and so the hunt begun to find a suitable solution.

I tried looking into some under the hood java functionality to help, but settled on another approach that seems to work pretty well, here's how it goes.

Our 'Beans' are all structured where their 'instance' data is in a variable structure i.e. etc.

I also have a generic method in my beans called 'getInstance' which returns a Structure containing all the instance data, it's a simple but powerful method that helps in debugging what data is contained in the Bean at a glance

...cffunction methog="getInstance" returntype="struct"

..cfreturn variables.instance


So I added a 'compareObject' method to my bean where I can pass in a bean of the same type and compare the 2 objects by introspecting the data from the 'getInstance' call on each of them and then simply looping through the structure keys and comparing them -
So regardless of whether the data is a date, numeric or string, the
<!--- Author: penny - Date: 6/9/2008 --->
<cffunction name="compareObject" output="false" access="public" returntype="boolean" hint="Compares 2 objects that have a getInstance Interface defined for them - ">
<cfargument name="ruleBean" type="ruleBean" required="true"/>

<!--- first compare the Structure Keys if that's the same (which they should be if they're the same object so let's ignore) --->
<!--- Next for each key in the Structure, compare the values - if there is one that is a non-match, then return a false and exit --->
<cfset var item = ''/>
<cfset var returnValue = true/>
<cfset var tmpObj =arguments.ruleBean.getInstance() />
<cfloop collection="#variables.instance#" item="item">
<cfif isSimpleValue(variables.instance[item])>
<cfif variables.instance[item] neq tmpObj[item]>
<cfset returnValue = false/>
<cfbreak/>
</cfif>
</cfif>
</cfloop>

<cfreturn returnValue />
</cffunction>


Note: this is calling 'isSimpleValue' to compare only numerics, boolean, datetime, strings and not Structures and Arrays, which simplifies the comparison scope, but may likely solve the 90% rule while leaving it up to you to implement or extend this method to do comparison accross your complex instance data.

So calling this is as simple as instantiating the bean, and calling the compareObject method on it, and passing in the bean you want to compare it to..

<cfset rule = createObject( "component", "ruleBean").init(1)/>
<cfset rule2 = createObject( "component", "ruleBean").init(2)/>
<cfset x =rule.compareObject(rule2) />
<cfdump var="#x#"/>

Returns 'false' as they are not equal (instance data in one object is '1' while the other is '2'.

Until we have a true 'compareObject' function to compare 2 objects, this will have to work for now.