開発する時のwwwrootの中

という訳で、僕はギークじゃないのでメインのマシンはWindowsです。(Macとか欲しいですけどね><)しかも、諸事情あって現在はあのVistaがメインです。だからなんだ、というと、僕のBlogに出てくるLocalパスは基本的に窓パスですよ、と。


で、Adobe ColdFusion8をインストールする際、IISに載せるのではなく独立したサーバにするようにすると、デフォルトでは[C:\ColdFusion8]というフォルダを作られます。ColdFusionの稼働に必要なもろもろがそこに置かれる訳ですが、その中に[wwwroot]というフォルダも作られます
言うまでもなく、CFMLで書いたコードを置く場所です。


ここに開発するコードを書いていく訳ですが、ColdFusionは基本的にブラウザからしか実行できない上、切り出したCFコンポーネントなんかも公開ディレクトリ配下(つまり上記の例で言うとC:\ColdFusion8\wwwroot以下)にないと使えないので、「ちょっと試してみたい事が・・・」と思っても、ルートのマジコードを作り込んでしまうと色々困った事になります。

Application.cfcというものがありまして、このファイルが置かれたディレクトリ以下の階層すべてに対してHTTPのリクエストを受ける度にこのApplication.cfcも実行されるという結構支配的な子です。
このApplication.cfcには、onApplicationStart-onApplicationEnd、onSessionStart-onSessionEnd、onRequestStart-onRequest-onRequestEndとonErrorというメソッドが定義可能で、これらを実装するとアプリケーションが最初にアクセスされた時(onApplicationStart)、アクセスされて既定の時間が経過した時(onApplicationEnd)、Session管理が有効な場合にWebAgentが最初にアプリケーションに触れた時(onSessionStart)、そのSessionがタイムアウトした時(onSessionEnd)、WebAgentからリクエストを受け取ったとき(onRequestStart-onRequest)、そのレスポンスを返す直前(onRequestEnd)と適宜これらのメソッドが実行されます。実装されなければ、何も起こりませんので、TemplateMethodパターンな感じに作られているんでしょうね。


例えばこんな感じのコードになります。

ファイル名がApplication.cfc

<cfcomponent>
...
	<cffunction name="onRequestStart" returntype="boolean">
		<cfargument name="TargetPage" type="string" required="true" />
		<cfreturn true />
	</cffunction>
...
</cfcomponent>

リクエストごとに必ずやらなくてはならない事(ログイン済かどうか、とか)を実装する場所としては良い場所ですが、例外的な扱いが必要な場合はそれを回避するif文を書くなりしてやる必要も出てくるので、ちゃんと取り扱いたい機能でもあります。

ルートの直下にこれを配置して、というのが基本的な使い方かなと個人的に思っています。


話を元に戻しますと、前述のようにルートの下にマジコードを作り込んでしまうと、お試しの為に作ったコードもこのApplication.cfcの支配下にはいります。なので、例えば前述の「ログイン済かどうか」という判定ロジックをここに実装していた場合、お試しコードもログインをしないと使えなくなります。これでは開発し辛いので、[wwwroot\app1]をアプリケーションのルートとして扱い、マジコードはその下に作り込んでいく、等としてます。(その際、お試しコードは[wwwroot\examples]などに作っていきます)
でないと、お試しコードを書いて挙動を確認する為に制約を実装しているApplication.cfcから派生させて、その制約を潰したApplication.cfcを作り、それをアプリケーションのルートの中に作ったディレクトリの直下に配置する等が必要になります。

Ex-1)何もしていない構成

  • wwwroot
    • index.cfm(←ログインの画面)
    • Application.cfc(←ここでindex.cfm以外ログインしてないと強制的に別サイトに飛ばす、とか実装)
    • dir1
      • sample.cfm(←ログインしていないと使えない><)


Ex-2)抜け道を作るべくApplication.cfcを拡張する

  • wwwroot
    • index.cfm
    • Application.cfc
    • dir1
      • Application.cfc(←上記制約を握りつぶす)
      • sample.cfm(←ログインしていなくてもアクセス可能)


Ex-3)個人的にお勧めしたい構成

  • wwwroot
    • app1
      • index.cfm
      • Application.cfc
    • sample
      • sample.cfm

こんな感じですね。index.cfmと同じようにロジックでdir1も弾けばイイジャン、と言う人はいないと思いますが、それをやると実際に本番稼動させようとした場合、dir1というディレクトリを消さなくてはならないし、Application.cfcにも手を入れなくてはなりません。(放置しても一応害はない筈ですが。。。)


でも、これで解決かというと実は別の問題が出ます。
CFコンポーネントの配置パスです。

上記Ex-3の例ですが、仮にこういった構成を取る必要があった場合。。。

  • wwwroot
    • app1
      • index.cfm
      • Application.cfc(←仮にa)
        • subsystem1
          • Application.cfc(←仮にb)
          • index.cfm
    • sample
      • sample.cfm

bのApplication.cfcは、aのApplication.cfcを継承して作る事になると思います。なので、まずアプリケーションルートにあるApplciation.cfcを継承したApplicationProxy.cfcを作成し(うろ覚えですが、確かApplication.cfcは同一ディレクトリ以外からはアクセスできなかったような気が)、bのApplication.cfcにはこのApplicationProxy.cfcを継承させます。

bのApplication.cfc

<cfcomponent extends="app1.ApplicationProxy">
...
</cfcomponent>

このextends属性の中にばっちり[app1]とリテラルで書かないといけません。いけないので、[app1]をコピーして[app2]を作ろうとした場合、ここを直してあげないといけないのです。

コンポーネントを指定して呼び出す箇所であれば、

<cfinvoke component="#APPLICATION.ApplicationName#.Hoge" method="foo" returnvariable="bar" />

といった形で実装可能なのですが、cfcomponentではやはり無理なようです。


cfneoの実装部分で、実はここに超困っていたりします><