Archive for the ‘Coldfusion’ Category

Case-sensitivity with Coldfusion and XML

Sunday, November 14th, 2010

This is really just a note about intermingling a case-insensitive language like Coldfusion with a case-sensitive language like XML. Sometimes I get so used to not having to pay attention to case when something goes wrong, that figuring out a simple issue that does have to do with case-sensitivity really throws me for a loop. The issue I ran into involved using the xmlSearch() function.

I used this function to search on an XML doc and the search kept returning an empty array. For a moment I thought for sure my xPath was incorrect, but further research showed it to be accurate. For some reason I just couldn’t get to a certain node. Of course, the issue turned out to be that I simply didn’t case my xPath correctly. For example my xPath may have looked like “//root/mynode”. The actual node I was trying to get in the XML doc was myNode.

Because I deal so much with Coldfusion I feel my immediate reaction to an xPath issue was that it was either wrong, or there was a misspelling. It really took a few minutes to realize that the path was correct as well as the spelling. What was incorrect was the case. Correcting the case, of course, resolved the issue.

So something to keep in mind, that while working within the world of Coldfusion case is meaningful only in terms of readability and following standards. However, when using Coldfusion with other (possibly case-sensitive) languages like XML we have to switch our brains into a different mode and start troubleshooting with character case in mind.

My First CF Builder Extension

Monday, November 8th, 2010

So I decided this evening to jump on the CF Builder Extension bandwagon and give it a shot myself. A quick look at the docs and a review of some of the pre-installed extensions that come with CF Builder and I was off and running.

I decided to start simple and create an extension that will allow the user (currently me) to select a set of characters and validate it as JSON.

Setting up a new extension is as simple as creating a new project, copying one of the existing extension configuration files (ide_config.xml) and creating a/some handlers. Extensions can be managed from the Extensions view in CF Builder. So my directory structure for my extension looks like the following.

/jsonValidator
/jsonValidator/ide_config.xml
/jsonValidator/handlers
/jsonValidator/handler/validateJson.cfm
/jsonValidator/handler/cfcs
/jsonValidator/handler/cfcs/handleValidation.cfc

That is the entire directory/file structure of my extension. Actually the handleValidation.cfc is not really needed as that code could be put inside of the validateJson.cfm file, but that wouldn’t be very good practice would it??

Let’s first take a look at the ide_config.xml file.

(more…)

Note on building CF Builder Extensions

Monday, November 8th, 2010

This is just a quick note concerning how you as a developer can approach the installation process of a CF Builder extension during development. Of course, while what you will eventually distribute to the world is a zip file containing your extension it doesn’t make much sense that you would need to zip and install the extension yourself with each update that you make during the development process.

CF Builder makes this process very simple in that it re-compiles the files with each save so that you don’t even need to use the Extensions view in CF Builder (although you should do an actual overwrite using the Extensions view when you have something complete). Anyways, just wanted to make sure that it was clear that you can develop and test your extension as if you were developing and testing in the browser. It may not seem like much, but it’s actually a really cool feature that makes our lives that much easier.

Switch/Case statement constants

Tuesday, November 2nd, 2010

This is more of a note than anything else concerning an error that throws when trying to run a switch case against a variable. Before analyzing this I want to simply display a function that illustrates a working switch statement, and then the same switch statement replacing the case value with a variable. Let’s take a look.

Working switch statement

public boolean function dynamicSwitch()
{
	var data1 = "matthew";
	var data2 = "cook";

	var expression = data1;

	switch(expression)
	{
		case "matthew":
		{
			return true;
		}

		default:
		{
			return false;
		}
	}
}

Throws an error

public boolean function dynamicSwitch()
{
	var data1 = "matthew";
	var data2 = "cook";

	var expression = data1;

	switch(expression)
	{
		case data1:
		{
			return true;
		}

		default:
		{
			return false;
		}
	}
}

So the second example uses the variable ‘data1′ as the value for the case. This throws a Coldfusion error indicating that case values must be constants (a hard-coded value). This makes sense, and maybe you’re wondering why a variable would ever need to be used for the case value. Admittedly, it certainly makes no sense in the above example, but I do personally like to declare all component constants at the top of my component by storing them in a ‘constant’ namespace and prefixing the variable name with a ‘c_’. Coldfusion doesn’t literally support constant variables, so having some rules around how to syntactically declare constant variables in Coldfusion makes sense to me.

So in my case I had set some constant variables in my component, and in a function needed to compare a passed in argument against them. It was a scenario where the value either would or would not equal the value of one of my constants. Hard-coding those values again for a switch statement would have been plain old bad practice. Nonetheless, it was also in this scenario that I learned I could not use a variable for my case value.

The result was that I used an if-else statement instead. It works fine. The switch statement would have been more appropriate, but take what you can get I guess.

String and Integer data typing catch using compare()

Monday, November 1st, 2010

I just previously wrote a post on the loose data typing in Coldfusion and how, although I could see the potential for problems, I have never actually had any issues that I’ve known about due to not having strict data typing. As fate would have it, of course, I ran into an issue today related to data typing using the Coldfusion compare() function. The issue is when two numbers get accidentally typed as a string behind the scenes and it doesn’t become known until you realize that there are inaccuracies in the comparison. It’s very important to note this because it almost made it past me.

The issue occurs when you compare the strings of integers and they get compared not as an integer, but as strings. The difference is that integers get compared as whole numbers, while strings get compared on a character by character basis. So for example comparing the string “3″ and the string “100″ will indicate that “100″ is less than “3″. The reason for this is because when looking at the first character “1″ is indeed less than “3″. Comparing the two as integers will of course indicate that 3 is less than 100.

So speaking more specific, the next thing to note is that the compare() function compares strings. This essentially makes it useless comparing integers. Maybe I’m wrong, but a quick search of the docs didn’t return any comparison function for integers. So the only way I know to handle it is to use an if/else statement. Let’s take a look at what we’re dealing with using the compare() function to compare either integers typed as strings or integers typed as integers, because the compare() function will implicitly type the data as strings.

String Comparison (cfscript)

public void function typeDataCatch()
	displayname="Type Data Catch" hint="Shows a data type catch using compare function." output="false"
{
	var data1 = "2";
	var data2 = "100";

	var dataComparison = compare(data1,data2);  //returns 1 indicating that 100 is less than 2
}

(more…)

Integer and String typing in Coldfusion

Monday, October 25th, 2010

Coldfusion is a loosely typed language meaning that, unlike many other languages, data types do not have to be typed explicitly. In Coldfusion the variable takes the type of the value that is assigned to it. For example, if a variable is created and set to structNew() that variable is typed as a struct since it has been clearly stated that the variable is to be a new struct.

While you can’t just go around concatenating and performing arithmetic on anything, like concatenating a string to a complex object or adding a number to a letter, Coldfusion will perform data typing changes on the fly for strings and numbers based upon the operation. Let’s take the following for example.

(more…)

Quick XML formatting with CF Builder

Sunday, October 17th, 2010

Pretty much every server-side language I’ve worked with has written XML to a file as compressed text. This is of course intentional in that any whitespace is indeed space and through the eyes of a program doesn’t matter. However, through the eyes of a human it does matter because large chunks of compressed xml is rather unreadable.

In the past I’ve always used Notepad++ to quickly format XML. However, this has always required opening the xml file in Notepad++ and formatting there. However, I just found in CF Builder the same feature. To use this you can either right-click anywhere in the editor containing the xml to be formatted and choose ‘Format’, or you can use the keyboard default shortcut “Shift-Command-F” on a mac or “Shift-Ctrl-F” on windows.

While I would recommend maintaining its compressed format in the file, this is a great feature for quickly making compressed XML readable.

Suppressing whitespace and saving content with cfscript

Monday, October 11th, 2010

I was writing a while back some script based components. In one function I needed to save some HTML content into a variable and I needed to make sure that the whitespace was controlled. In tag-based CF it would look something like the following.

<cfprocessingdirective suppresswhitespace="true">
	<cfoutput>
		<cfsavecontent variable="loc_data">
			<div>
				<p>
					This is some HTML content!
				</p>
			</div>
		</cfsavecontent>
	</cfoutput>
</cfprocessingdirective>

When I went to look up the documentation on how to write the equivalent of this in script the relevant bits and pieces were few and far between. So I ended up just trying some different ways of writing it that made sense and sure enough the processingdirective tag does have a script equivalent. The script version of this will look like the following. It’s actually much simpler and cleaner if you ask my opinion.

processingdirective suppresswhitespace=true
{
	savecontent variable="this_data"
	{
		writeOutput('<div><p>This is some HTML content!</p></div>');
	}
}

So in the end pretty simple. The documentation just isn’t very user friendly on the cfscript end. Hopefully this will get better as it is a cleaner way to write components.

duplicateDirectory() UDF

Saturday, October 2nd, 2010

For a project I’m working on I needed to grab an existing directory and duplicate it to another location. My quick search through the Coldfusion docs didn’t return any methods that would allow me to do this. As a result, I built one that is fairly simple. It accepts two arguments: 1. directory to copy, and 2. the directory to copy to. Let’s first take a look at the function itself.

<cffunction name="duplicateDirectory" displayname="Duplicate Directory" hint="Duplicates the specifed directory in another specified directory." access="private" output="false" returntype="void">

    <cfargument name="directoryToCopy" displayname="Directory To Copy" hint="The full path to the directory that is to be duplicated." type="string" required="true" />
    <cfargument name="directoryToCopyTo" displayname="Directory To Copy To" hint="The full path to the directory that the duplicated directory is to be copied to." type="string" required="true" />

    <cfset var loc_dirList = "" />
    <cfset var loc_rootDir = listLast(arguments.directoryToCopy, "/") />
    <cfset var loc_thisRootDir = arguments.directoryToCopyTo & "/" & loc_rootDir />
    <cfset var loc_thisDirName = "" />
    <cfset var loc_thisDirPath = "" />
    <cfset var loc_thisFileName = "" />
    <cfset var loc_thisFilePath = "" />
    <cfset var loc_createThisDir = "" />
    <cfset var loc_createThisFile = "" />
    <cfset var loc_i = 0 />
    <cfset var loc_dirExt = "" />
    <cfset var loc_record = false />

    <!--- create this root directory --->
    <cfdirectory action="create" directory="#loc_thisRootDir#" />

    <!--- get a list of everything in the directory to copy.  **IMPORTANT: sort by 'type' and then 'directory' to ensure that all directories in the root are created before any directories
    insde of those directories.  After all directories have been created then the files can be copied over. --->
    <cfdirectory action="list" name="loc_dirList" recurse="true" directory="#arguments.directoryToCopy#" sort="type, directory" />

    <!--- loop over all directories and files --->
    <cfloop query="loc_dirList">
        <!--- determine if a file or directory --->
        <cfif type eq "dir">
            <!--- set the name and path --->
            <cfset loc_thisDirName = name />
            <cfset loc_thisDirPath = directory />

            <cfset loc_dirExt = "" />

            <cfset loc_record = false />

            <!--- get the dir structure after the root dir --->
            <cfloop list="#loc_thisDirPath#" delimiters="/" index="loc_i">
                <cfif loc_i eq loc_rootDir>
                    <cfset loc_record = true />
                </cfif>

                <cfif loc_record eq true>
                    <cfset loc_dirExt = loc_dirExt & "/" & loc_i />
                </cfif>
            </cfloop>

            <!--- set the path to create the directory --->
            <cfset loc_createThisDir = arguments.directoryToCopyTo & loc_dirExt & "/" & loc_thisDirName />

            <!--- create the directory --->
            <cfdirectory action="create" directory="#loc_createThisDir#" />
        <cfelse>
            <cfset loc_thisFileName = name />
            <cfset loc_thisFilePath = directory />

            <cfset loc_dirExt = "" />

            <cfset loc_record = false />

            <!--- get the dir structure after the root dir --->
            <cfloop list="#loc_thisFilePath#" delimiters="/" index="loc_i">
                <cfif loc_i eq loc_rootDir>
                    <cfset loc_record = true />
                </cfif>

                <cfif loc_record eq true>
                    <cfset loc_dirExt = loc_dirExt & "/" & loc_i />
                </cfif>
            </cfloop>

            <!--- set the desination path for the file to be copied to --->
            <cfset loc_createThisFile = arguments.directoryToCopyTo & loc_dirExt />

            <!--- copy the file to its project destination --->
            <cffile action="copy" source="#loc_thisFilePath#/#loc_thisFileName#" destination="#loc_createThisFile#" />
        </cfif>
    </cfloop>

</cffunction>

So an example of calling this function would look something like:

<cfset variables.existingDirPath = expandPath("./") & "/templates/mytemplate" />
<cfset variables.copyDirToPath = expandPath("./") & "/duplicates" />

<cfset duplicateDirectory(variables.existingDirPath, variables.copyDirToPath) />

Also, in case you prefer using script, the same function can a be written as the following. Take your pick. **do note that most likely the cfscript version will not work on CF7MX or CF8. I believe the tag based one should work on all three versions.

component
{
	public void function duplicateDirectory(required string directoryToCopy, required string directoryToCopyTo)
	{
		var loc_dirList = "";
		var loc_rootDir = listLast(arguments.directoryToCopy, "/");
		var loc_thisRootDir = arguments.directoryToCopyTo & "/" & loc_rootDir;
		var loc_thisDirName = "";
		var loc_thisDirPath = "";
		var loc_thisFileName = "";
		var loc_thisFilePath = "";
		var loc_createThisDir = "";
		var loc_createThisFile = "";
		var loc_i = 0;
		var loc_j = 0;
		var loc_dirExt = "";
		var loc_record = false;
		var loc_fileToCopy = "";

		//check if the directory exists
		if(directoryExists(loc_thisRootDir))
		{
			//delete the directory
			directoryDelete(loc_thisRootDir, true);
		}

		//create this root directory
		directoryCreate(loc_thisRootDir);

		//get a list of all directories/files in the root directory being copied
		loc_dirList = directoryList(arguments.directoryToCopy, true, "query", "", "type, directory");

		//loop over the query of directories and files
		for(loc_i = 1; loc_i <= loc_dirList.recordcount; loc_i++)
		{
			//check if a directory or a file
			if(loc_dirList["type"][loc_i] == "dir")
			{
				loc_thisDirName = loc_dirList["name"][loc_i];
				loc_thisDirPath = loc_dirList["directory"][loc_i];

				loc_dirExt = "";
				loc_record = false;

				//loop over the directory structure and get anything after the root
				for(loc_j = 1; loc_j <= listLen(loc_thisDirPath, "/"); loc_j++)
				{
					//if the root directory has been reached
					if(listGetAt(loc_thisDirPath, loc_j, "/") == loc_rootDir)
					{
						loc_record = true;
					}

					if(loc_record == true)
					{
						loc_dirExt = loc_dirExt & "/" & listGetAt(loc_thisDirPath, loc_j, "/");
					}
				}

				//set path of the directory to create
				loc_createThisDir = arguments.directoryToCopyTo & loc_dirExt & "/" & loc_thisDirName;

				//create the directory
				directoryCreate(loc_createThisDir);
			}
			else
			{
				loc_thisFileName = loc_dirList["name"][loc_i];
				loc_thisFilePath = loc_dirList["directory"][loc_i];

				loc_dirExt = "";
				loc_record = false;

				for(loc_j = 1; loc_j <= listLen(loc_thisFilePath, "/"); loc_j++)
				{
					if(listGetAt(loc_thisFilePath, loc_j, "/") == loc_rootDir)
					{
						loc_record = true;
					}

					if(loc_record == true)
					{
						loc_dirExt = loc_dirExt & "/" & listGetAt(loc_thisFilePath, loc_j, "/");
					}
				}

				//create path of the file to create
				loc_createThisFile = arguments.directoryToCopyTo & loc_dirExt;

				//set the location of the file to be copied
				loc_fileToCopy = loc_thisFilePath & "/" & loc_thisFileName;

				//create copy the file to its new destination
				fileCopy(loc_fileToCopy, loc_createThisFile);
			}
		}
	}
}

I haven’t had a chance to test this on anything outside of my current project. So if anyone runs into any troubles using please post and I can update appropriately.

So feel free to use and adapt this as you please!

CF9 getMetadata() function caching

Wednesday, September 22nd, 2010

I’ve been working on an application that utilizes the getMetadata() function. I’m building this to run on CF7, 8, and 9 so I cannot utilize the new getComponentMetadata() function in CF9. However, were I working only with CF9 I would definitely utilize this function as it doesn’t require the component being introspected to be instantiated first. Anyways, when I began using the getMetadata() function with CF9 I noticed some annoying caching behavior. After playing around with it a little I realized that it was caching somewhere other than the usual places because I couldn’t get rid of the previous instances.

Come to find out that in the Administrator I had caching turned on for components and the trusted cache where I believe it was being stored. I turned off both caches, cleared them and now it runs as expected. I’ll note that my expectation was that each time I passed in a new component instance I would get the metadata and only the metadata for that instance.

I’ll also note that caching does serve a purpose, which is to speed up page load and processing times. As such, unless you are testing caching directly is it necessarily needed to run caching in the development environment. However, I would definitely recommend keeping caching turned on in the production environment, unless there is some specific reason not to.