CFMLとCFScriptの書き方の違い

# CFMLとCFScriptの書き方の違い

## どんな話？

CFMLとCFScriptの書き方の違いを書いています。
CFMLで書いているものをCFScriptで書き換える場合はどんな感じ？みたいな。

## CFML⇒CFScript に置き換える方法は、主に2つ

ColdFusionタグと同等の機能をCFScriptで記述する際、2つの方法があるようです。

1. タグ名をそのままCFScriptとして記述
1. タグと同等の機能を持つ関数などを利用する

2.については、以下の公式マニュアルに一部記載されています。
[タグに相当するCFScript機能](https://helpx.adobe.com/jp/coldfusion/developing-applications/the-cfml-programming-language/extending-coldfusion-pages-with-cfml-scripting/what-is-supported-in-cfscript.html)（日本語）

ただ、色々ググると上記には乗っていない情報も結構あります。
ColdFusion関連のことはググっても、

## タグ名をそのままCFScriptとして記述する方法

**※この記述方法はColdfusion11から利用可能**
例えば`cfcontent`タグはこんな感じで書くと思います。

```xml
<!--- CFML --->
<cfcontent reset="true">
```

これをCFScriptで書きたい場合は、こんな感じになります。

```cfscript
// CFScript
cfcontent(reset="true");
```

ほぼタグのような書き方ですね。

パラメータが2つ以上ある場合は、カンマ区切りで書きます。例として`cfexecute`タグを。

```xml
<!--- CFML --->
<cfexecute name="hogeApp" argument="-fuga" outputFile="C:\Temp\result.txt" timeout="30">
```

```cfscript
// CFScript
cfexecute(name="hogeApp", argument="-fuga", outputFile="C:\Temp\result.txt", timeout="30");
```

CFMLをCFScriptに置き換えたい場合、まずはこんな感じで書いていくといいと思います。


## タグと同等の機能を持つ関数などを利用する

タグ名をそのままCFScriptとして記述する方法以外に、
CFMLタグと同等の（または似たような）機能を利用する方法もあります。
他言語の経験者ならこちらの方がわかりやすそうです。

以下にいくつか記載します。
（ifなど、関数というよりはCFScriptを用いた構文の書き方みたいなものもあります）

|CFML|CFScript|
|---|---|
|[cfabort](#cfabort)|abort|
|[cfcomponent](#cfcomponent)|component|
|[cfdump](#cfdump)|WriteDump|
|[cffile](#cffile)|FileRead<br>FileWrite<br>など...|
|[cffunction](#cffunction)|function|
|[cfif, cfelseif, cfelse](#cfif-cfelseif-cfelse)|if, elseif, else|
|[cfinclude](#cfinclude)|include|
|[cfmail](#cfmail)|mail|
|[cfquery, cfqueryparam](#cfquery-cfqueryparam)|QueryExequte|
|[cfreturn](#cfreturn)|return|

以下、記述例とリファレンスのリンクを紹介。
リファレンスにリンクしていますが、日本語があるものと無いものがあるんですね・・・

-----

### cfabort

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-a-b/cfabort.html)（英語）

  ```xml
  <cfabort>
  ```

CFScript

```cfscript
abort;
```

タグ名からcfを抜いたもの、そのまんまですね。

-----

### cfcomponent

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-c/cfcomponent.html)（英語）

```xml
<cfcomponent displayname="hoge" hint="fuga" output="false">
  (関数などを定義)
</cfcomponent>
```

[CFScript](https://helpx.adobe.com/coldfusion/developing-applications/the-cfml-programming-language/extending-coldfusion-pages-with-cfml-scripting/defining-components-and-functions-in-cfscript.html)（英語、functionと同じ）

```cfscript
component displayname="hoge" hint="fuga" output="false" {
  (関数などを定義)
}
```

これは関数と言うか、CFScriptを用いたコンポーネントの生成方法ですね。
属性として`displayname`などを例に挙げていますが、他の属性でも同じような書き方です。
もちろん、使わないなら書く必要はありません。

-----

### cfdump

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-d-e/cfdump.html)（英語）

```xml
<cfdump var="hoge">
```

CFScript

```cfscript
WriteDump(hoge);
```

`Dump`ではなく`WriteDump`です。
`output`や`format`などのパラメータは使ったことがないので、気が向いたら調べて追記しておきます。

-----

### cffile

[CFML](https://helpx.adobe.com/jp/coldfusion/cfml-reference/coldfusion-tags/tags-f/cffile.html)（日本語）
- [write](https://helpx.adobe.com/jp/coldfusion/cfml-reference/coldfusion-tags/tags-f/cffile-action-write.html)
- [read](https://helpx.adobe.com/jp/coldfusion/cfml-reference/coldfusion-tags/tags-f/cffile-action-read.html)

```xml
<!--- ファイルに文字列「ほげほげふがふが」を書き込み --->
<cffile action="write" file="c:\files\hoge.txt" output="ほげほげふがふが" charset="utf-8">

<!--- 変数hogeにファイルの内容を読み込み --->
<cffile action="read" file="c:\files\hoge.txt" variable="hoge" charset="utf-8">
```

CFScript（以下2つともに英語）
- [FileWrite](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-e-g/filewrite.html)
- [FileRead](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-e-g/fileread.html)

```cfscript
// ファイルに文字列「ほげほげふがふが」を書き込み
FileWrite("c:\files\hoge.txt", "ほげほげふがふが", "utf-8");

// 変数hogeにファイルの内容を読み込み
hoge = FileRead("c:\files\hoge.txt", "utf-8");
```

cffileはいくつかの動作がありますが、例としてとりあえず書き込みと読み込みだけ。
他も似たような感じで書けます。

-----

### cffunction

[CFML(cffunction)](https://helpx.adobe.com/jp/coldfusion/cfml-reference/coldfusion-tags/tags-f/cffunction.html)（日本語）
[CFML(cfargument)](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-a-b/cfargument.html)（英語）

```xml
<cffunction name="hoge" access="private" returnType="query">
  <cfargument name="fuga" required="true" type="string" default="ABC">
  (処理)
</cffunction>

```

[CFScript](https://helpx.adobe.com/coldfusion/developing-applications/the-cfml-programming-language/extending-coldfusion-pages-with-cfml-scripting/defining-components-and-functions-in-cfscript.html)（英語、componentと同じ）

```cfscript
private query function hoge(required string fuga="ABC") {
  (処理)
}
```

`component`同様、関数と言うよりはCFScriptを用いた関数の定義方法ですね。
アクセス修飾子や引数の`required`など、CFMLで省略できるものはCFScriptでも省略できます。
そのうち、アクセス修飾子が`remote`の場合の引数の受け取り方なども書きたいですね。

-----

### cfif, cfelseif, cfelse

[CFML(cfif)](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-i/cfif.html)（英語）

```xml
<cfif hoge EQ 1>
  （処理1）
<cfelseif hoge GT 1>
  （処理2）
<cfelse>
  （処理3）
</cfif>
```

CFScript

```cfscript
if (hoge == 1) {
  （処理1）
} elseif (hoge > 1) {
  （処理2）
} else {
  （処理3）
}
```

これも関数ではないですね。CFScriptを用いたif構文の書き方です。
CFScriptだと`>`などを使って比較もできるので、多言語慣れしている方にはより書きやすいかなと。
参考: [式：開発ガイド](https://helpx.adobe.com/jp/coldfusion/developing-applications/the-cfml-programming-language/using-expressions-and-number-signs/expressions-developing-guide.html)（日本語）

-----

### cfinclude

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-i/cfinclude.html)（英語）

```xml
<cfinclude template="hogehogepath" runOnce="true">
```

CFScript

```cfscript
include "hogehogepath" runOnce = "true";
```

`runOnce`は省略可能。省略した場合はfalseと同じ動きをするようです。

-----

### cfmail

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-m-o/cfmail.html)（英語）

```xml
<cfmail server="hoge" from="fuga" to="piyo" subject="foo">
  メール本文
</cfmail>
```

[CFScript](https://helpx.adobe.com/coldfusion/cfml-reference/script-functions-implemented-as-cfcs/mail.html)（英語）

```cfscript
var mail = new mail(
  server = "hoge",
  from = "fuga",
  to = "piyo",
  subject = "foo"
  body = "メール本文"
);
mail.send();
```

インスタンスを生成して、そのメソッドを使って送信、と言った感じですね。
インスタンス生成は`new mail()`の代わりに`createObject("component", "mail")`とも書けます。

~~また、作成したオブジェクトに対して、後からfromを変更したい場合は、
`mail.setAttribute('from', 'fugafuga')`
または
`mail.setFrom('fugafuga')`
のように書くこともできるようです。
引数が多いのはちょっと嫌な方は、後者のような書き方のほうがきれいに書けると思います。~~

**2022/1/25訂正**
先に示したリンク先のドキュメントには
`setAttribute()`や`setParam()`メソッドが定義されているようですが、
ColdFusion2018でパラメータ"to"の動作を確認したところ、
`setAttribute()`は使えず（そんなメソッドは無い的な例外）、
`setParam()`は動作するものの設定されないようです。
（ColdFusion2021なら動くのかな・・・時間がある時に確認してみます）

パラメータtoの場合は`setTo()`メソッドを使うなど、
いくつかのパラメータについては`setHoge()`メソッドが用意されています。
（すべて可能ではないですが、from、to、cc、bcc、subject、body、removeは専用のメソッドで設定可能であることを確認）

メール添付については、こんな感じで行けると思います。

```cfscript
mail.addParam(file = ファイルパス, type = "text/plainなどファイルに合わせたもの");

// メール送信後にファイルを削除する場合
mail.setRemove(true);
```

まあ、もう少し調査が必要ですね・・・

-----

### cfquery, cfqueryparam

[CFML(cfquery)](https://helpx.adobe.com/jp/coldfusion/cfml-reference/coldfusion-tags/tags-p-q/cfquery.html)（日本語）

```xml
<cfquery name="hoge" datasource="fuga" result="piyo">
  SELECT * FROM HOGEHOGE
  WHERE COLUMN1 = <cfqueryparam value="ABC" CFSQLType="CF_SQL_NVARCHAR">
  AND COLUMN2 = <cfqueryparam value="DEF" CFSQLType="CF_SQL_NVARCHAR">
</cfquery>
```

[CFScript](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-m-r/queryexecute.html)（英語）

```cfscript
hoge = QueryExecute("
    SELECT * FROM HOGEHOGE
    WHERE COLUMN1 = :value1
    AND COLUMN2 = :value2
",
{
    value1 = {value = "ABC", CFSQLType = "CF_SQL_NVARCHER"},
    value2 = {value = "DEF", CFSQLType = "CF_SQL_NVARCHER"}
},
{
    datasource = "fuga",
    result = "piyo"
});
```

改行やインデントはお好みで・・・
使わないなら、第2引数（cfqueryparamにあたるもの）や第3引数（datasourceとか）は省略できます。
上に書いていないパラメータも似たような感じで書けるはずです。
SQLのパラメータ部分の書き方は、CFSQLTypeを省略するならもっと簡単に書けたりもするので、
[リファレンス（英語）](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-m-r/queryexecute.html)をチラ見してみるといいかもしれません。

第3引数を指定することはあまりないかもしれません。
`datasource`は省略すればApplication.cfcで指定した値を使いますし、`result`は以下のような方法でも取得できますので。

```cfscript
// 方法その1
result = QueryGetResult(hoge);

// 方法その2
result = hoge.GetResult();
```

参考: [QueryGetResult](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-m-r/querygetresult.html)（英語）

-----

### cfreturn

[CFML](https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-r-s/cfreturn.html)（英語）

```xml
<cfreturn hoge>
```

CFScript

```cfscript
return hoge;
```

これはそのまんま。他言語とほぼ同じ書き方ですね。

-----

## 終わりに
何年かぶりにColdFusionを触ることになって、色々忘れてしまった。
ColdFusionのお仕事ってCFMLベースで書くことが多く、
あまりCFScriptが使われていないと思います（個人の感想です）が、
他言語慣れしていると（ビュー部分以外は）CFScriptのほうが書きやすいですね。