Mojaviの呪縛

昨日のSkypeミーティングで、Actionフィルターでbefore/afterメソッドを呼ぶようにするかという議論の際に以下のような指摘がでた。

  • Actionフィルターは最後に追加されるという特別扱いは今となっては違和感がある
  • 現在エラーがあったらexecuteをスキップするということが固定になっているが、これも場合によっては逆の動きもできるという柔軟性があってもいいのではないか?
  • このあたりの動きをまずは整理した後、どうするかを考えてもいいのでは?

Actionフィルターを最後に追加するというものはMojaviからいただいたアイディアだが、それを特別扱いする必要性はないどころか、それによる弊害もでてきているのかなと。

また、Actionフィルターで複数のことを処理しているからActionフィルターを改造してbefore/afterを呼ぶようにしようという発想になったのであって、もっと細分化されていればexecute()を呼ぶ前に普通にFilterでフックできたはずである。

ということで、Mapleがいろいろアイディアを拝借しているWebWork2をみてみると、以下のようなInterceptorが存在する。

Interceptor名 機能
static-params Actionに対して設定ファイルで指定した値をセットする
params Actionに対してリクエストパラメータをセットする
component Actionに対してコンポーネントをセットする
workflow Validationに失敗した場合、Actionを実行せずにINPUTのビューに遷移する
prepare Actionのprepareメソッドを実行する

上記のように現在Actionフィルターがまとめてやっている処理が細分化されている。確かにここまで細分化されていれば、executeの前にフックを入れるとか、リクエストパラメータとコンポーネントをセットする順番を制御できる。

ここまで細分化すると毎回指定するのが大変だろうということになるが、Webwork2では複数のInterceptorの実行順をあらかじめ規定したInterceptorStackというのを定義できる。つまり、「static-parmas⇒params⇒component⇒prepare⇒workflow」というInterceptorStackを定義しておいて、それをInterceptorとして使えば、指定も楽になるという形だ。

ならばということで、Mapleでも現在のActionフィルターを以下のように細分化し、Actionフィルターが最後に呼ばれるという特例もはずすということにしてはどうかと考えている(フィルター名は仮です)。

Filter名 機能
Filter_StaticParams Actionに固定値をInjectionする
Filter_Params ActionにリクエストパラメータをInjectionする
Filter_Component ActionにComponentをInjectionする
Filter_Action Actionのexecuteメソッドを実行し、responseにview_typeを設定
Filter_BeforeAction Actionのbeforeメソッドを実行する
Filter_AfterAction Actionのafterメソッドを実行する

新しいActionフィルターでは、以下のような指定ができるようにするといいのではないだろうか。デフォルトの動作を「onError = skip」としてエラーが既に発生していればexecuteを実行せずに、「onError = execute」とするとエラー発生時にもexecuteを実行できるという形となる。同じようにbefore/afterも作っておけば、エラー時の動作を制御できる。

[Action]
onError = execute

ここまで細分化されたら指定が大変だという点に関しては、WebWork2のInterceptorStackのような解決策ではなくて、maple.iniの継承機能で対処でいいかなと。

※知っている人は知っている継承機能ですが、Mapleでは上位の階層のmaple.iniを引き継ぐという機能があります。例えば foo_bar というActionの場合、webapp/modules/foo/bar/maple.ini が使用されますが、webapp/modules/foo/maple.iniが存在した場合その設定を先に使用します。これはどんどん上の階層をみますので最終的にwebapp/modules/maple.iniを定義しておけば全てのActionに共通のFilterをかけることができます。

という風に考えたのですが、どうでしょうか?どちらにしろ大きな動作変更になるので、3.2ではなくて、3.5での変更ですかね。