Skip to content

Latest commit

 

History

History
1269 lines (1046 loc) · 33.9 KB

cfscript.md

File metadata and controls

1269 lines (1046 loc) · 33.9 KB

Table of Contents

CFScript documentation

This attempts to document all of CFScript, as a resource for people migrating from old-school tag-based code to script-based code. The reason I am doing this is because neither ColdFusion nor Railo/Lucee provide much (or in the case of Railo/Lucee: any) useful documentation of CFScript.

This is not a document for converting tags to script. It is not written from a point of view of "if you use <cfsometag> then you need to instead use [some script construct]". It simply documents CFScript.

There are some syntax-neutral solutions to some CFML constructs which are listed at the bottom of the document. These are the CFCs found in [customtag]/com/adobe/coldfusion. These are not CFScript constructs per se, but related enough to be relevant here.

It is also not an exercise in teaching CFML (or at least the script part). It assumes you know what you're doing, and is purely a reference.

I assume Railo 4.2/Lucee 4.5 or ColdFusion 11, except where stated.

Comments

// single line comment
a=1; // single line comment at end of line
/*
    multiple
    line
    comment
*/
/*
    multiple line
    /* comments */
    cannot be nested
*/

In this case, the commented bit is /* multiple line /* comments */, making the next bit a syntax error.

Statements

Statements end in semi-colons:

a = 1;

Semi-colons are generally optional on Railo/Lucee:

a = 1

Where "generally" means "if the end of the statement is unambiguous without a semi-colon". It is better to just always use semi-colons.

Block statements (with curly braces) do not have semi-colons:

while (condition) {
    // statements
}

Variables

Assigning a variable:

varName = "foo";

Assigning a function-local variable:

var varName = "foo"; // analogous to local.varName =  "foo";

Note that the var keyword can appear inline in most statements where a variable is first initialised, eg:

for (var i=1; i <= 10; i++);

Assigning a dynamically-named variable:

varName = "foo";
"#varName#" = "bar";
writeOutput(foo); // bar

trycf-logo Run this example on trycf.com

This is the same as with a <cfset> tag, but confuses some people due to it being slightly odd-looking. Obviously one can also use associative array syntax too (eg: variables[varName] = "bar";. This is preferable as it's more clear what's going on).

Defaulting a variable:

param numeric variableName=defaultValue; // where "numeric" could be any type

For more complex situations:

param name="variableName" type="regex" pattern="."; // any cfparam attribute is supported

Operators

All operators available to tag-based code still work in CFScript. In addition, CFScript has these ones:

Decision

a == 1; // equality
a < 1;  // less than
a <= 1; // less-than-or-equal
a >= 1; // greater-than-or-equal
a > 1;  // greater than
a != 1; // inequality
a <> 1; // inequality (Railo/Lucee only)

trycf-logo Run this example on trycf.com

Arithemetic

Increment/decrement
// increment
a = 1;
b = a++; // b=1, a=2    // postfix operators returns value, then peforms action (in this case: increments a)
c = ++a; // c=3, a=3    // prefix operator peforms action then returns result
// decrement
a--; // a=2
--a; // a=1

trycf-logo Run this example on trycf.com

Inline assignment
a += 2; // equivalent to a=a+2
a -= 3; // equivalent to a=a-3
a *= 4; // equivalent to a=a*4
a /= 5; // equivalent to a=a/5
a %= 6; // equivalent to a=a%6
s &= "a"; // equivalent to s = s & "a"

trycf-logo Run this example on trycf.com

Boolean

!a;     // NOT a
a && b; // a AND b
a || b; // a OR b

trycf-logo Run this example on trycf.com

Decision

Ternary operator
result = condition ? trueExpression : falseExpression;

//eg:
coinTossResult = randRange(0,1) ? "heads" : "tails";

trycf-logo Run this example on trycf.com

// NB: only one of trueExpression or falseExpression is evaluated:
a = 1;
b = 1;
c = false ? ++a : ++b; // a=1, b=2, c=2

trycf-logo Run this example on trycf.com

Null-coalescing variation
result = left ?: right; // left-hand expression is used unless it is null, in which case the right one is used

//eg:
a = d ?: "default"; // a = default

trycf-logo Run this example on trycf.com

d = 1;
a = d ?: "default"; // a = 1

trycf-logo Run this example on trycf.com

Note that whilst this appears to be the same as other language's "Elvis" operator, it is not the same. The "Elvis" operator checks for false (and in some languages null is falsey); this operator checks specifically for null. This is likely due to a misunderstanding one the part of Adobe (and perpetuated by the Lucee devs when copying it).

Conditions

if/elseif/else

if (booleanExpression)
    // single statement executed if booleanExpression is true
else if (anotherBooleanExpression)
    // single statement executed if anotherBooleanExpression is true
else
    // single statement executed if condition(s) are false
if (booleanExpression) {
    // multiple statements executed if booleanExpression is true
} else if (anotherBooleanExpression) {
    // multiple statements executed if anotherBooleanExpression is true
} else {
    // multiple statements executed if condition(s) are false
}

trycf-logo Run this example on trycf.com

switch

switch (expression) {
    case "some constant value": // value can be dynamic on Railo/Lucee
         // statements executed if expression = "some constant value"
    break; // exit switch statement
    case "a different constant value":
        // statements executed if expression = "a different constant value"
        // if there is no break, then processing continues to execute statements until a break is encountered...
        // ... but subsequent case evaluations are not made. A switch is basically a GOTO mechanism, which does a...
        // single GOTO the first matching case. It is NOT a series of if/elseif/else statements
    case "third constant value":
        // statements executed if expression = "a different constant value" or "third constant value"
    break;
    case "4th value":
    case "5th value":
            // statements executed if expression is one of "4th value" or "5th value"
    break;
    default:
        // statements executed if no case was fulfilled (or if the last fulfilled case did not have a break)
    break;
}

trycf-logo Run this example on trycf.com

try/catch/finally, throw/rethrow

try {
    // statements

    throw "message"; // throws an Application exception, with the given message

    // or
    throw (type="ExceptionType", message="message", detail="detail", errorCode="errorCode", extendedInfo="extendedInfo"); // despite appearances, this is NOT a function

    // or
    throw (object=JavaExceptionObject);
}
catch (SomeExceptionType variableContainingExceptionObject) {
    // statements executed if code in try block errors with a SomeExceptionType exception

    rethrow; // rethrows the caught exception
}
catch (SomeOtherExceptionType variableCOntainingExceptionObject) {
    // statements executed if code in try block errors with a SomeOtherExceptionType exception
}
catch (any variableCOntainingExceptionObject) {
    // statements executed if code in try block errors with any not-yet-caught exception type
}
finally {
    // statements executed in any case, INCLUDING unhandled exceptions. This code ALWAYS runs
}

Iteration

General-purpose for loop

for (initialisation; condition; repetition) statement;

or:

for (initialisation; condition; repetition) {
    // statements
}

EG:

for (i=1; i <=5; i++) writeOutput(i); // just the following single statement is looped over

or:

for (i=1; i <=5; i++) {
    // all statements within the block are looped over
    result = i * 2;
    writeOutput(result);
}

The general perception is that this is the only form of a general-purpose for() loop: initialising a counter variable, testing it and adjusting it (increment, decrement). This is not the case. Each of the statements can be anything (the condition needs to evaluate to a boolean), and indeed are optional. This is an endless loop, equivalent to while (true):

for (;;)

A very contrived example to demonstrate the freedom one has with the parameters of the for():

i=0;
for (; true; writeOutput(i)) {
    if (++i > 5) break;
}

In general, all looping constructs have either the single-statement or block-of-statements syntax. I'll only offer the more common (and recommended, for code-clarity) block syntax henceforth.

Pre-condition loop

This form of loop evaluates a single condition at the beginning of each iteration, and continues to loop whilst the condition is true:

while (condition) {
    // statements
}

This form of loop will execute zero or more times.

Post-condition loop

This form of loop evaluates a single condition at the beginning of each iteration, and continues to loop whilst the condition is true:

do {
    // statements
} while (condition);

This form of loop will execute one or more times. It's important to consider that the body of the loop will always run the first time, because no condition is evaluated until the end of the loop.

Array loop

For statement
for (element in [1,2,3,4,5]) {
    writeOutput(element); // 12345
}
arrayEach()
arrayEach(["a","b","c"], function(element,index,array) {
    writeOutput("#index#:#element#;"); // 1:a;2:b;3:c;
});
Array.each()
a = ["a","b","c"];
a.each(function(element,index,array) {
    writeOutput("#index#:#element#;"); // 1:a;2:b;3:c;
});

Note that Railo/Lucee can call methods directly on a literal, so this works:

["a","b","c"].each(function(element,index,array) {
    writeOutput("#index#:#element#;"); // 1:a;2:b;3:c;
});

Struct loop

For statement
struct = {a=1,b=2,c=3};
for (key in struct) {
    writeOutput("#key#:#struct[key]#;"); // a:1;b:2;c:3; (order of keys not guaranteed, obviously)
}
structEach()
structEach(struct, function(key,value,struct) {
    writeOutput("#key#:#value#;"); // a:1;b:2;c:3;
});
Struct.each()
struct.each(function(key,value,struct) {
    writeOutput("#key#:#value#;"); // a:1;b:2;c:3;
});

Query loop

q = queryNew("id,data", "integer,varchar",[
    [11, "aa"],
    [22, "bb"],
    [33, "cc"]
]);
for (row in q){
    writeOutput("#q.currentRow#:#row.id#:#row.data#;"); // 1:11:aa;2:22:bb;3:33:cc;
}

Using grouping:

q = queryNew("pk,fk,data", "integer,integer,varchar",[
    [1, 10, "aa"],
    [2, 20, "bb"],
    [3, 20, "cc"],
    [4, 30, "dd"],
    [5, 30, "ee"],
    [6, 30, "ff"]
]);
cfloop(query=q, group="fk") {
    writeOutput("<strong>#fk#</strong>");
    cfloop() {
        writeOutput("#pk#:#data#<br>");
    }
    writeOutput("<hr>");
}

Railo/Lucee only:

loop query=q group="fk" {
    writeOutput("<strong>#fk#</strong>");
    loop {
        writeOutput("#pk#:#data#<br>");
    }
    writeOutput("<hr>");
}

List loop

list = "a;b;c";
listEach(list, function(element,index,list) {
    writeOutput("#index#:#element#;"); // 1:a;2:b;3:c;
}, ";");

// or

list.each(function(element,index,list) {
    writeOutput("#index#:#element#;"); // 1:a;2:b;3:c;
}, ";");

// or (ColdFusion only, see [RAILO-3207](https://issues.jboss.org/browse/RAILO-3207))

for (element in "a,b,c,d,e") {
    writeOutput(element); // abcde
}

I am not sure how one would specify a delimiter for the last example: it does not seem supported.

Railo/Lucee only:

cfloop(list="a;b;c", index="element", delimiters=";") {
    writeOutput(element); // abc
}

// or
loop list="a;b;c" index="element" delimiters=";" {
    writeOutput(element); // abc
}

File loop

filePath = getCurrentTemplatePath();
cfloop(file=filePath, index="chars", characters=16, charset="UTF-8"){
    writeOutput(chars); // outputs the contents of this file
}

Railo/Lucee only:

loop file=filePath index="chars" characters=16 charset="UTF-8" {
    writeOutput(chars);
}

Date/time range loop

ColdFusion has no specific CFScript-specific construct for this as of ColdFusion 11

Work around:

from = now();
to   = dateAdd("d", 7, from);

for (date=from; dateCompare(date, to, "d") <= 0; date = dateAdd("d", 1, date)) {
    writeOutput(dateTimeFormat(date, "yyyy-mm-dd HH:nn:sstt") & "<br>");
}

Railo/Lucee only:

cfloop(from=from, to=to, index="date", step=createTimespan(1,0,0,0)) {
    writeOutput(dateTimeFormat(date, "yyyy-mm-dd HH:nn:sstt") & "<br>");
}

// or

loop from=from to=to index="date" step=createTimespan(1,0,0,0) {
    writeOutput(dateTimeFormat(date, "yyyy-mm-dd HH:nn:sstt") & "<br>");
}

Iteration flow control

cfcontinue:

for (i=1; i <= 5; i++) {
    writeOutput("#i# is ");
    if (i mod 2) {
        writeOutput("ODD<br>");
        continue;
    }
    writeOutput("EVEN<br>");
}

Other flow control statements

Request Redirect

/* cflocation */
// ColdFusion
location(url="http://example.com", statuscode="301 OR 302", addtoken=false);

// Railo/Lucee
location url="http://example.com", statuscode="301 OR 302", addtoken=false;

Abort processing

abort;

// or

abort "error message";

Exit from current file

exit;

//or

exit "method";

Code reuse

Include

include "pathToFile";

// or

include "pathToFile" runonce=true;

Module

// Railo/Lucee
module template="inc.cfm" attr1="val1" attr2="val2";

// ColdFusion
cfmodule(template="inc.cfm", attr1="val1", attr2="val2");

Components / interfaces

component {

}

Attributes

component extends="Parent" {

}

Or:

/**
 * @extends Parent
 */
component {

}

Note that the comment for annotations is /** not simply /*.

Also note that the latter syntax does not currently work on Railo (see RAILO-3169).

Interface

interface {
    public void function f(required numeric x); // note no braces, and ends with semi-colon
}

Properties

Basic:

property string myProperty;

With additional parameters:

property type="string" name="myProperty" default="default value"; // and all the same attributes as `<cfproprty>`

Functions

Basic:

function f() { // assumes public function, returntype any

}

With access and return type modifiers:

private void function f() {
    // statements
}

Arguments

Basic:

function f(x) { // optional argument of type "any"
    //statements
}

Type:

function f(numeric x) { // optional argument of type "numeric"
    //statements
}

Required:

function f(required numeric x) { // required argument of type "numeric"
    // statements
}

Default value:

function f(numeric x = 0) { // optional argument of type "numeric" with default value of 0
    // statements
}

Function/argument annotations

/**
 * @x.hint hint for argument x
 * @x.type numeric
 * @x.required true
 */
function f(x) {
    // statements
}

Note these annotations do not current correctly work on Railo (see RAILO-3170)

Also note that this does not currently work on ColdFusion (see 3808960)

/**
 * @x.type numeric
 * @x.default 0 // this causes a compile error
 */
function f(x) {
    // statements
}

Function expressions

f = function(x) {
    // statements
};

Functions defined by function expressions use closure, functions defined by a function statement do not

Annotations for function expressions are not supported on ColdFusion (3808978); are supported on Railo, but have same shortcomings as noted above.

Calling functions dynamically

test = new Test();
methodToCall = "f";
argumentsToPass = {x=1};
result = invoke(test, methodToCall, argumentsToPass);

Railo/Lucee-only:

result = test[methodToCall](argumentCollection=argumentsToPass);

Import

import com.domain.app.package.*;

Object creation

myObj = createObject(type, "path.to.class"); // along with other type/situation-specific arguments

// or

myObj = new path.to.some.cfc.file(); // NB: will call the CFC's init() (by default), or method identified by the initmethod attribute of the component (bug in Railo: [RAILO-2294](https://issues.jboss.org/browse/RAILO-2294))

File system operations

Directories

// simple directory creation
directoryCreate("path/to/directory");
// using other optional attributes
cfdirectory(action="create", directory="path/to/directory", mode="777");
// Railo/Lucee only
directory action="create" directory="path/to/directory" mode="777";
// delete
directoryDelete("path/to/directory");
// list
listing = directoryList("path/to/directory", true, "query", "*.cfm", "size desc"); // CF11 added an additional "type" attribute. Not currently supported on Railo/Lucee
// rename
directoryRename("path/to/directory", "path/to/new/directory");

Files

// read
// text
if (fileExists("path/to/file")) {
   result = fileRead("path/to/file");
}

// or
fileHandle = fileOpen("path/to/file", "read");
result = fileRead(fileHandle, bytesToRead);
fileClose(fileHandle);

// or
fileHandle = fileOpen("path/to/file", "read");
while (!fileIsEOF(fileHandle)) {
    result = fileReadLine(fileHandle);
}
fileClose(fileHandle);
// binary
result = fileReadBinary("path/to/file");

//or
fileHandle = fileOpen("path/to/file", "readbinary");
result = fileRead(fileHandle, bytesToRead);
// append
fileHandle = fileOpen("path/to/file", "append");
fileWrite(fileHandle, textToAppend);
fileClose(fileHandle);
// copy
fileCopy("path/to/file", "path/to/copyOfFile");
// delete
fileDelete("path/to/file");
// move / rename
fileMove("path/to/file", "new/path/to/file");
// upload
fileUpload("path/to/upload/file/to");
fileUpload(destination [, fileField [, accept [, nameConflict]]]);

fileUploadAll("path/to/upload/files/to");
fileUploadAll(destination [, fileField [, accept [, nameConflict]]]);
// write
fileWrite("path/to/file", data);

// or

fileWrite(fileHandle, data);

Database

Query

// general form
recordset = queryExecute(sqlString, params, options);
// with params array
numbers = queryExecute("
    SELECT    columns
    FROM    table
    WHERE    id BETWEEN ? AND ?
",
[1,4],
{
    datasource    ="myDsn",
    result        = "result"    // this is analogous to the result attribute of `<cfquery>`
});
// with params struct
numbers = queryExecute("
    SELECT    columns
    FROM    table
    WHERE    id BETWEEN :low AND :high
",{low=2,high=3});

To qualify parameters with SQL types you can specify the equivalent of the cfqueryparam options with the parameters in the following way:

// with sql types in params struct
numbers = queryExecute("
    SELECT    columns
    FROM    table
    WHERE    id BETWEEN :low AND :high
",
{
    low = { value = 2,
            cfsqltype = "cf_sql_integer"
        },
    high = { value = 3,
             cfsqltype = "cf_sql_integer"
        }
});

For versions prior to ColdFusion 11 (in which queryExecute() was implemented), there is a CFC-based solution: Query.cfc. An example is as follows:

numbers = new Query(
    sql            = "
        SELECT    columns
        FROM    table
        WHERE    id BETWEEN :low AND :high
    ",
    parameters    =[
        {name="low", value=2},
        {name="high", value=3}
    ]
).execute().getResult();

Stored Procedure

cfstoredproc(procedure="procName") {
    cfprocparam(type="in", cfsqltype="cf_sql_varchar", value="someValue");
    cfprocresult(name="result",resultSet=1);
    cfprocresult(name="result2",resultSet=2);
}

Railo/Lucee only

storedproc procedure="procName" 
    dataSource = "myDataSource" 
    result="response" 
    returncode="true" {
    procparam type="in" cfsqltype="cf_sql_varchar" value="someValue";
    procparam type="out" cfsqltype="cf_sql_integer" variable="myVariable";
    procresult resultSet=1 name="result";
    procresult resultSet=2 name="result2";
}

There is a change request you should vote for, to implement this syntax:

options = {
    datasource = "scratch_mssql",
    fetchclientinfo = true,
    returncode = true
};
params = [
    {value=URL.low, type="INTEGER"},
    {value=URL.high, type="INTEGER"},
    {type="out", variable="inclusiveCount", type="INTEGER"},
    {type="out", variable="exclusiveCount", type="INTEGER"}
];

result = executeProcedure("uspGetColours", params, options);

See ColdFusion ticket: 3791737; Railo ticket: RAILO-3184, and earlier blog article: 'ColdFusion 11: calling a stored procedure from script. And can we please stop wearing out our "c" and "f" keys?'.

Insert

Railo/Lucee only:

insert datasource="myDataSource" tableName="myTable" formFields="list,of,form,fields"; // arguments the same as `<cfinsert>`. datasource is optional

Note: there is a bug with this: RAILO-3180.

ColdFusion only:

cfinsert(datasource="myDataSource", tableName="myTable", formFields="list,of,form,fields"); // arguments the same as `<cfinsert>`

Note that datasource is currently required, which is a bug: 3814079.

Update

Railo/Lucee only:

update datasource="myDataSource" table="myTable" formFields="list,of,form,fields"; // arguments the same as `<cfupdate>`. datasource is optional

Note the same bug applies here as does with insert.

ColdFusion only:

cfupdate(datasource="myDataSource", table="myTable", formFields="list,of,form,fields"); // arguments the same as `<cfupdate>`

DB Info

cfdbinfo(type="tables", name="info"); // arguments the same as `<cfdbinfo>`

Railo/Lucee only:

dbinfo type="tables" name="info"; // arguments the same as `<cfdbinfo>`

Transactions

transaction {
    try {
        // stuff to do
        transaction action="commit";
    }
    catch (any e) {
        transaction action="rollback";
    }
}

Note that all attributes of <cftransaction> are supported as space-separated name/value pairs.

Debugging

Dump

writeDump(myVar); // can use either ordered or named arguments.

With named arguments:

writeDump(var=myVar, output=ExpandPath('/debug/log.txt'));

Railo/Lucee only:

dump(myVar)

Log

writeLog("text to log"); // can use either ordered or named arguments.

Trace

// Railo/Lucee only
trace category="test" text="trace text" { // plus all same params as `<cftrace>`
    // stuff to trace
}
// COLDFUSION only
trace(category="test", text="trace text") { // plus all same params as `<cftrace>`
    // stuff to trace
}
// note that CF11 incorrectly records timing information (see [3811003](https://bugbase.adobe.com/index.cfm?event=bug&id=3811003))

Timer

cftimer(label="timer label" type="outline") { // plus all same params as `<cftimer>`
    // stuff to time
}
// Railo/Lucee only
timer label="timer label" type="outline" { // plus all same params as `<cftimer>`
    // stuff to time
}

General / Miscellaneous

Output

writeOutput(expression); // expression must resolve to a string

Railo/Lucee only:

echo(expression); // expression must resolve to a string

File Encoding

pageencoding "UTF-8";

Note that this only works in CFC files on ColdFusion (3712167). It works correctly on Railo/Lucee.

Save content

savecontent variable="saved" {
    writeOutput("stuff to save");
}

Threading

thread action="run" name="threadName" {
    // code to run in separate thread here
}
thread action="join" name="threadName,anotherThreadName";

Locking

lock name="lockName" timeout=1 throwontimeout=true {
    // code to lock
}

Image / XLS manipulation

The function equivalents of <cfimage> and <cfspreadsheet> are all well documented, and are not specifically CFScript constructs.

PDF Manipulation

I have to concede I have never ever done any work with PDFs, so cannot make an informed comment on the CFScript equivalents. However in lieu of particular CFScript-specific constructs that I am aware of, the generic syntax ought to work, eg:

ColdFusion:

cfdocument(format="PDF") {
    // mark-up here
}

Railo/Lucee:

document format="PDF" {
    // mark-up here
}

The same should work on other PDF-oriented tags. For versions of ColdFusion prior to CF11, there is a PDF.cfc (similar to Query.cfc, and also in cfusion/CustomTags/com/adobe/coldfusion). I have never used it, do not know how it works, and have no interest in finding out. If someone would like to donate some example code, I will integrate it here.

Elements of tag-based CFML with no specific CFScript implementation

CFC-based solutions

As far as I can tell, there is no CFScript-specific implementations for the following pieces of functionality:

  • <cfftp>
  • <cfpop>
  • <cfimap>
  • <cffeed>
  • <cfldap>
  • <cfcollection>
  • <cfindex>
  • <cfsearch>

There are CFC wrappers for these in cfusion/CustomTags/com/adobe/coldfusion. These are not CFScript-specific solutions per se - one can just as easily use them in tag-based code - but can be included here for the sake of completeness. I personally do not use these constructs, and as they are not part of CFScript, did not attempt to include them here. Feel free to document and include them if you so choose.

http.cfc

ColdFusion (CF9+):

The pattern seems to be set{ATTRIBUTENAME}( value ); for setting attributes that are normally set via the <cfhttp> tag

// there's a built-in CFC that handles this in CF9+
httpService = new http();
httpService.setMethod( "post" )
httpService.setCharset( "utf-8" );

// the API provider may require you to export this cert
// so you’ll need to save it in a secure place…
// and reference it here
httpService.setClientCert( "#ExpandPath(‘.’)#/my_cert.p12" );
httpService.setClientCertPassword( "mypassword!" );
httpService.setUrl( "https://api.sample.com/" );

// these params are form fields to POST
httpService.addParam(type="formfield", name="field1", value="1111");
httpService.addParam(type="formfield", name="field2", value="some text here");

// this is the cfscript way to grab the response
httpResponse = httpService.send().getPrefix();

writeDump(httpResponse);

mail.cfc

ColdFusion (CF9+):

The pattern seems to be set{ATTRIBUTENAME}( value ); for setting attributes that are normally set via the <cfmail> tag

mailerService = new mail();
/* set mail attributes using implicit setters provided */
mailerService.setType("html");
mailerService.setCharset( "utf-8" );
mailerService.setTo( "adam@sample.com" );
mailerService.setFrom( "test@sample.com;joe@sample.com" );
mailerService.setSubject( "Super interesting subject" );

/* add mailparams */
mailerService.addParam( file=expandpath(form.attachment), type="text/plain", remove=false );
// create the body
savecontent variable="mailBody"{
    WriteDump( CGI );
    WriteDump( SESSION );
}
// send the email
mailerService.send( body=mailBody );

The rest

To use any other functionality not listed here within CFScript, one needs to use the generalised syntax.

On Railo/Lucee this is a matter of removing the "<cf" and the ">", and using normal block syntax (curly braces) where the tag-version is a block-oriented tag.

On ColdFusion (CF11+), replace the "<cftagname" with "cftagname(", and the ">" with ")", and comma-separate the attributes. Note that this will make the construct look like a function, but it actually is not, and cannot be used like a function, eg this is invalid syntax:

result = cfhttp(method="post", url="http://example.com");

Some tags take a block of code / text within them. Blocks are represented with curly braces, similar to a flow-contrl statement.

cfmail(attributeCollection = attributesforCfmail) {
	cfmailpart(type="text/plain") {
		writeOutput("If you are seeing this, your e-mail client does not support HTML messages.");
	}
	cfmailpart(type="text/html") {
		writeOutput(htmlVersionOfMessage);
	}
}

Note how text needs to be "output" using writeOutput. Note also how sub-tags (cfmailpart here) are also expressed using the same rules as parent tags.


Creative Commons License This work is licensed under a Creative Commons Attribution 4.0 International License.