In my work environment we have ColdFusion 7 and I like to write my templates in cfscript, but since CF7 does not support some new scripting functions in CF8, I wrote a component to mimic those functions and allow me to stay focused on the scripting.
Well, it is not my original idea, I saw it from other blogs, but I added some value to it with some additional functions.
You may download the component here
First of all, I instantiate the component as a local variable called CF, then I call it from the script as cf.functionName.
Here is the list of functions available in the component:
- directory: cf.directory(action, directory, newdirectory, sort, recurse,filter)
- file: cf.file(action, file, output, source, destination, charset)
- dump: cf.dump(var, label, expand)
- abort: cf.abort()
- query: cf.query(query, datasource)
- location: cf.location(url, addToken)
- flush: cf.flush(interval) do not use it if you have a cflocation in your template otherwise the cflocation will not work.
- trace: cf.trace(text, interval, crlf) used to display messages on screen during the process for debugging purposes. Same as cf.flush, if you use it, any cflocation in your template will not work.
- mailIt: cf.mailIt(mailFrom, mailTo, subject, msg, failTo, mailType) sends email messages
- postError: cf.postError(message, sendMail, withTrace, abort, cfLogFile, webmasterEmail, errorType, thread, date, time, aplication, template, line) logs the error, sends message, abort, etc.
- fileWriteUTF8: cf.fileWriteUTF8(sFilePath, sInput) creates an empty text file with the BOM header for UTF-8, then you can append to it using cf.file
Here is the component:<cfcomponent>
<cfset this.logFile = "myLogFile" />
<cfset this.webmasterEmail = "webmaster@myDomain.com" />
<cfset this.applicationName = "myApplication" />
<cffunction name="resultInit" access="private" output="false" returntype="Any">
<cfscript>
result = structNew();
result.status = true;
result.content = "";
return result;
</cfscript>
</cffunction>
<cffunction name="directory" access="remote" output="true" returntype="any">
<cfargument name="action" type="string" required="true" />
<cfargument name="directory" type="string" required="true" />
<cfargument name="newdirectory" type="string" required="false" default="" />
<cfargument name="sort" type="string" required="false" default="name asc" />
<cfargument name="recurse" type="string" required="false" default="false" />
<cfargument name="filter" type="string" required="false" default="" />
<cfset result = resultInit() />
<cfswitch expression="#arguments.action#">
<cfcase value="create">
<cftry>
<cflock name="cfdirectory" type="exclusive" timeout="10">
<cfdirectory action="create" directory="#arguments.directory#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="delete">
<cftry>
<cflock name="cfdirectory" type="exclusive" timeout="10">
<cfdirectory action="delete" directory="#arguments.directory#" />
</cflock>
<cfcatch type="any">
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="rename">
<cftry>
<cflock name="cfdirectory" type="exclusive" timeout="10">
<cfdirectory action="rename" directory="#arguments.directory#" newdirectory="#arguments.newdirectory#" />
</cflock>
<cfcatch type="any">
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="list">
<cftry>
<cflock name="cfdirectory" type="readonly" timeout="10">
<cfdirectory action="list" directory="#arguments.directory#" name="result.content" sort="#arguments.sort#" filter="#arguments.filter#" recurse="#arguments.recurse#" />
</cflock>
<cfcatch type="any">
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfdefaultcase>
<cfset result.status = false />
<cfset result.content = structNew() />
<cfset result.content.message = "Invalid operation requested!" />
<cfset result.content.detail = "" />
</cfdefaultcase>
</cfswitch>
<cfreturn result />
</cffunction>
<cffunction name="file" access="remote" output="true" returntype="any">
<cfargument name="action" type="string" required="true" default="read" />
<cfargument name="file" type="string" required="false" default="" />
<cfargument name="output" type="string" required="false" default="" />
<cfargument name="source" type="string" required="false" default="" />
<cfargument name="destination" type="string" required="false" default="" />
<cfargument name="charset" type="string" required="false" default="UTF-8" />
<cfset result = resultInit() />
<cfswitch expression="#arguments.action#">
<cfcase value="write">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="write" file="#arguments.file#" output="#arguments.output#" charset="#arguments.charset#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="copy">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="copy" source="#arguments.source#" destination="#arguments.destination#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="rename">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="rename" source="#arguments.source#" destination="#arguments.destination#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="move">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="move" source="#arguments.source#" destination="#arguments.destination#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="delete">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="delete" file="#arguments.file#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="read">
<cftry>
<cflock name="myComponent-cffile" type="readonly" timeout="10">
<cffile action="read" file="#arguments.file#" variable="result.content" charset="#arguments.charset#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfcase value="append">
<cftry>
<cflock name="myComponent-cffile" type="exclusive" timeout="10">
<cffile action="append" file="#arguments.file#" output="#arguments.output#" />
</cflock>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
</cfcase>
<cfdefaultcase>
<cfset result.status = false />
<cfset result.content = structNew() />
<cfset result.content.message = "Invalid operation requested!" />
<cfset result.content.detail = "" />
</cfdefaultcase>
</cfswitch>
<cfreturn result />
</cffunction>
<cffunction name="dump" access="remote" output="true" returntype="any">
<cfargument name="var" type="any" required="true" />
<cfargument name="label" type="string" required="false" default="" />
<cfargument name="expand" type="boolean" required="false" default="true" />
<cfdump var="#arguments.var#" label="#arguments.label#" expand="#arguments.expand#" />
</cffunction>
<cffunction name="abort" access="remote" output="false" returntype="any">
<cfabort />
</cffunction>
<cffunction name="query" access="remote" output="false" returntype="Any">
<cfargument name="query" type="string" required="true" />
<cfargument name="datasource" type="string" required="false" default="#application.mainDSN#" />
<cfset result = resultInit() />
<cftry>
<cfquery name="result.content" datasource="#arguments.datasource#">
#arguments.query#
</cfquery>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
<cfreturn result />
</cffunction>
<cffunction name="location" access="remote" output="true" returntype="Any">
<cfargument name="url" type="string" required="true" />
<cfargument name="addToken" type="boolean" required="false" default="false" />
<cflocation url="#arguments.url#" addtoken="#arguments.addToken#" />
</cffunction>
<cffunction name="flush" access="remote" output="true" returntype="Any">
<cfargument name="interval" type="numeric" required="false" default="10" />
<cfflush interval="#arguments.interval#" />
</cffunction>
<cffunction name="trace" access="remote" output="true" returntype="Any">
<cfargument name="text" type="string" required="true" />
<cfargument name="interval" type="numeric" required="false" default="10" />
<cfargument name="crlf" type="boolean" required="false" default="true" />
<cfoutput><cfif arguments.crlf><br/></cfif>#arguments.text#</cfoutput>
<cfflush interval="#arguments.interval#" />
</cffunction>
<cffunction name="mailIt" access="remote" output="false" returntype="Any">
<cfargument name="mailFrom" type="string" required="true" />
<cfargument name="mailTo" type="string" required="true" />
<cfargument name="subject" type="string" required="true" />
<cfargument name="msg" type="string" required="true" />
<cfargument name="failTo" type="string" required="false" default="#this.webmasterEmail#" />
<cfargument name="mailType" type="string" required="false" default="html" />
<cfset result = resultInit() />
<cftry>
<cfmail from="#arguments.mailFrom#" to="#arguments.mailTo#" failto="#arguments.failTo#" subject="#arguments.subject#" type="#arguments.mailType#">
#arguments.msg#
</cfmail>
<cfcatch>
<cfset result.status = false />
<cfset result.content = cfcatch />
</cfcatch>
</cftry>
<cfreturn result />
</cffunction>
<cffunction name="postError" access="remote" output="true" returntype="any">
<cfargument name="message" required="true" type="string" />
<cfargument name="sendMail" required="false" type="boolean" default="false" />
<cfargument name="withTrace" required="false" type="boolean" default="false" />
<cfargument name="abort" required="false" type="boolean" default="false" />
<cfargument name="cfLogFile" required="false" type="string" default="#this.applicationName#" />
<cfargument name="webmasterEmail" required="false" type="string" default="#this.webmasterEmail#" />
<cfargument name="errorType" required="false" type="string" default="Any" />
<cfargument name="thread" required="false" type="string" default="true" />
<cfargument name="date" required="false" type="string" default="true" />
<cfargument name="time" required="false" type="string" default="true" />
<cfargument name="application" required="false" type="string" default="true" />
<cfargument name="template" required="false" type="string" default="" />
<cfargument name="line" required="false" type="string" default="" />
<cfset result = resultInit() />
<cfif len(trim(arguments.cfLogFile))>
<cflog file="#arguments.cfLogFile#" application="#arguments.application#" type="#arguments.errorType#"
text="#arguments.message#" />
<cfelse>
<cflog log="Application" application="#arguments.application#" type="#arguments.errorType#"
text="#arguments.message#" />
</cfif>
<cfif arguments.sendMail>
<cfsavecontent variable="msg">
<cfoutput>
<body>
<head>
<title>Error Message</title>
</head>
<div id="wrapper">
<div id="title">ERROR Occurred in #this.applicationName#</div>
<div id="text">Message time stamp: #dateFormat(now(),"yyyy-mm-dd")# #timeFormat(now(),"HH:mm:ss")#</div>
<cfif len(trim(arguments.template))>
<div id="template">Template: #arguments.template#</div>
</cfif>
<cfif len(trim(arguments.line))>
<div id="line">Line: #arguments.line#</div>
</cfif>
<div id="text">#arguments.message#</div>
</div>
</body>
</cfoutput>
</cfsavecontent>
<cfset result = mailIt("errorHandler@myDomain.com", "#arguments.webmasterEmail#", "Error occurred in #this.applicationName#", "#msg#") />
</cfif>
<cfif arguments.withTrace>
<cfset trace(arguments.message) />
</cfif>
<cfif arguments.abort>
<cfabort />
</cfif>
<cfreturn result />
</cffunction>
<cffunction name="fileWriteUTF8" access="remote" output="false" returntype="Any">
<cfargument name="sFilePath" type="string" required="true" />
<cfargument name="sInput" type="string" required="true" />
<cfscript>
// declare jWrite object
var jWriter = "";
// create the file stream
var jFile = createobject("java", "java.io.File").init(sFilePath);
var jStream = createobject("java", "java.io.FileOutputStream").init(jFile);
result = resultInit();
try {
// output the UTF-8 BOM byte by byte directly to the stream
jStream.write(239); // 0xEF
jStream.write(187); // 0xBB
jStream.write(191); // 0xBF
// create the UTF-8 file writer and write the file contents
jWriter = createobject("java", "java.io.OutputStreamWriter");
jWriter.init(jStream, "UTF-8");
jWriter.write(sInput);
// flush the output, clean up and close
jWriter.flush();
jWriter.close();
jStream.close();
} catch (Any excpt) {
result.status = false;
result.content = excpt;
}
return result;
</cfscript>
</cffunction>
</cfcomponent>
So, from my template I will call the cffile function for example like this:
<cfscript>
cf = createObject("component","cffunctions");
result = cf.file(action="read" file=expandPath(myFile.txt);
if (not result.status) cf.postError (result.content.message & "<br />" & result.content.detail, true, true, true); // this will log the error, send a message, show on screen and abort
myDoc = result.content;
</cfscript>
Another example, listing a directory and deleting its contents:
<cfscript>
result = cf.directory(action="list", directory=expandPath(myDirectory), filter="*.jpg");
if (not result.status) cf.postError(result.content.message & "<br/>" & result.content.detail, true, true, true); it logs error, sends message, outputs error and aborts
qDir = result.content;
for (i=1; i lte qDir.recordCount; i=i+1){
result = cf.file(action="delete", file=qDir.directory[i] & "\" & qdir.name[i]);
if (not result.status) cf.postError(result.content.message & "<br/>" & result.content.detail, true, true, false); // it logs error, sends message, output error and continue without aborting
}
Generating a UTF-8 file with BOM header:
<cfscript>
result = cf.fileWriteUTF8(expandPath(myFile.xml), '<?xml version="1.0" encoding="UTF-8"?>');
if (not result.status) cf.postError(result.content.message & " - " result.content.detail, true, true, true);
//.... here you add your logic to generate the content for the file
result = cf.file(action="append", file=expandPath(myFile.xml), output=myContent, newLine=true);
if (not result.status) cf.postError(result.content.message & " - " result.content.detail, true, true, true);
</cfscript>
Feel free to add more functions to the component, but please don’t forget to send me a copy so I can update mine too.
This is good stuff.. Im a big fan of cfscript, this’ll open up some limitations. Thanks! (I found this site looking for dump() (figured why reinvent the wheel…))