タイトル/名前 | 更新者 | 更新日 |
---|---|---|
日記/2007/08/31/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:28:21 |
日記/2007/08/29/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:27:37 |
日記/2007/08/19/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:26:37 |
日記/2007/08/13/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:24:27 |
日記/2007/08/10/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:22:57 |
日記/2007/08/05/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:19:13 |
日記/2007/07/31/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:16:43 |
日記/2007/07/29/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:13:37 |
日記/2007/07/22/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:10:00 |
日記/2007/07/21/Xhwlayメモ | msakamoto-sf | 2008-12-23 00:07:52 |
駄目だ。色々あって、手が動かない。いや、精神的に。
焦って出してもしょうもない代物(全く個人的な代物)ではあるので、もうちょっと熟成させる。というか、ちゃんと準備してから出そう。ドキュメントも。あと、出すなら最初からPEARチャネル立てちゃえ、と。INSTALL手順書き直すの面倒くさいので。
というか、SF.netでMySQLの利用申請だしてなかったから、PEARチャネル立ち上げるならまずはそこからだったりする。
WEB+DB PRESSの33号、が詳しいらしい。
ようやく、LICENSEファイルの追加とlicense termの主要PHPファイルへの挿入をcommitできた。あと、svn:keywordsのId属性を付けてなかったメインPHP系も
$ svn propset svn:keywords Id *.php
で付けまくった。っつーか、最初
$ svn propset keywords Id *.php
ってやってて、「置換されない・・・おかしいな・・・」とか悩んでたのがアホクサ。ignoreかexecutableの時も間違ってたよな。
Tutorialは書いている最中だけど、やっぱ間に合いそうにない。1.0.0に回す。0.9.0自体、内輪向けの活動報告みたいなモノだし。
明日か明後日辺りphpDocのテンプレートを整えて、Webと一緒に出しちゃおうか。
っつーか、やっぱり土曜日埋められると・・・日曜日、動けなくなるので、きつい。
頭が・・・Event driven stateful page flow に完全に作り替えられてる・・・。駄目だ、もう。今までの"Action-Page mapping"なアプリケーションを、作れなくなってる。
なので、相当疲れた。Wizardのサンプルとして用意したEvent-drivenのmain.phpを焼き直すのは意味がない。・・・というか、Page orientedな方での作り込みをするのが久しぶりなので、いざやろうとすると忘れかけてたり、あとは実際に思い出して作ろうとするとなんだか面倒くさくなってやる気が起きなかったり。
だって・・・前までの作りだと、ActionではGETとPOST両方受け、内部で「GETなら画面表示用の処理」「POSTなら値をセットして次頁にLocationさせて・・・」ってやってたんだけど、 駄目だわ。すげー面倒くさくなってる。 実装箇所がずれただけでコレか。
そもそもXhwlayでのPage orientedな機能はあくまでもオプショナル。Xhwlayが使っている"Bookmark"のコンセプトは、別にEvent-Drivenじゃなくても、以前通りの"Action-Page mapping"な作り方でも機能しますよ~~~という只のリップサービス。(まあ、作り始めた最初の頃はこちらが本道で、Event-Drivenは全然考えてなかったんだけど。)
なのであまり凝ったサンプルを作っても、その分報われるかというと疑問。なので、まあ単純に、"next"で遷移先を制限できますよ~とか、Validateしたければ"Barrier"を定義して下さいね~とか、あとlogin.phpやmain.phpで省略してた、独自にクラスロードしたい場合はこのHOOKを差し込んで下さいね~とかの非常に単純なサンプルになった。
あと、作り上、Bookmark-OFFでも動くようにしておいた。"Bookmark-OFF"のサンプルも作るのが面倒くさかったので、兼用。
残りはライセンス条文の埋め込みと、ドキュメント。
というわけで、とりあえず簡単なログイン・ログアウトサンプルと、ウィザード形式のサンプルをfixしました。
どうでも良いですが、"<button>"タグ、便利~~~。何で今まで知らなかったんだよ、コンチキショーなみに便利。だって、<input>タグのsubmitボタンだけじゃ、複数のボタンがあったときに渡す値を切り替えることが(JavaScript無しでは)不可能だったんだもん・・・。
というわけで、特にWizardサンプルについてはもうそちらに切り替えました。
あと、Wizardサンプルについては、戻ったり進んだりしてるとPOST-Backでややこしくなるので、まあwipeout()の試験も兼ねてSubmit -> Event発生 -> Location ヘッダー送出 -> wipeout()でそのまま終了。みたいなルートも実装してみました。これでhistory-backされても再POSTのMessageBoxは表示されなくなります。
あと、Subversionをいよいよ使い始めたのですが・・・どうも、$Id$などのキーワード置換が上手く行かない。
$ svn propset svn:keywords Id *.php
ってやって、一度commitしてみたんだけど、ローカルファイル上では
* $Id: main.php 5 2007-08-12 15:15:42Z msakamoto-sf $
となってるけど、sourceforgeのViewVCでWeb上でリポジトリのソースを閲覧してみると、"$Id$"のまんま。・・・これってひょっとして、CheckoutとかCommit時にSVNのクライアント側で置換をしてくれるのかな?
あと、svn:executableが設定されていたので
$ svn propdel executable *.php
とか試しにsampleでやってみたんだけど、消せない・・・。
って、
$ svn propdel svn:executable *.php
の間違いだった・・・orz。
これでexecutableを消せました。どうでも良いけど、gVim(6.4, Windows版)で編集して保存すると、Cygwin上で見てみると勝手に実行属性が付いてしまう・・・。なんで?
まあ、SVNが取り扱う実行属性は、svn:executableのみによって管理されるから、ファイルシステム上で実行権限がどうなっていようと、要はsvn:executableの有無だけに気をつけていればよいのでまあどうでもいいといえば良いのだけれど。"svn status"でも、そこ(ファイルシステム上の実行権限の有無の変更)は見ていないみたいだし。
sampleも、あと二つ。Page-Action mappingタイプ(オールドタイプと呼ぼう。・・・どうでもいいか。)のサンプルと、Bookmark-OFFモードのオールドタイプサンプルを。
今週はあまり時間が取れなかったけど、SVNへインポートできたので、8月中の予定(というか優先順位について)簡単にまとめる。
取得例:
$ svn checkout https://xhwlay.svn.sourceforge.net/svnroot/xhwlay/xhwlay-php
・・・こんな感じかな・・・。
まあ、9/1のPHPカンファレンス迄に、最低限度の目鼻立ちは整えるぞ、という感じで。
前回のsymfonyのセミナーより、断然面白い。
「オブジェクト指向わかんねー」とか、Javaの文法は知ってるけど「abstractとかinterfaceとかの使い方が分からない」とか悩んでるうちの社員を連れて行きたかった・・・。
内容的には自分にとっては「おさらい+弱点補強+アイデアGET」で、ほどよく満足。また、テスト駆動開発で「最初から考えすぎない」という点は自分、まだまだだなぁ・・・と。やっぱり、考えてしまうからな・・・。変化に対して強くなる為のツールとして自動化テストツールが使えるわけだから、まあ、あんまり考え過ぎなくても良いじゃないか。クライアントI/Fがしっかり動いていれば・・・。それに、リファクタリングした後のデグレ対策はテストツールでまかなえるんだし。ということなんだろうな・・・。
結構早くできあがった方かも知れない。5月末に暴走が始まって、6月初旬からコードを弄りだして。平日、まあ3 - 4日ほど家帰ったあと1 - 1.5時間ほど?あと、日曜日にまあ、7 - 8時間ほど?かけてちまちま作ってきたとはいえ、まあ、早いかも。
いや、やってることの小ささに比べたら遅いかも。まあ、いろいろそれなりにアレコレ悩んだりしてたから・・・。
現状、とりあえずログイン・ログアウト、あと簡単なウィザード形式の二つが出来上がった。つっても、kubo様にお見せする為大急ぎででっちあげたやつだけど。なので、セッション管理とか全部デフォルト。つまり、手抜きも良いところ。まあ、Xhwlayの動作確認はできる。
残るはもう少しきちんとExampleを整備して、あと何点か追加して。あとは、phpDocでドキュメントを生成。で、sf.netのCVSに登録。WebサイトはとりあえずphpDocで生成したのと、適当な簡単な説明・紹介ページだけでいいや。freshmeatにも、まだ流さない。
気が済むまでやる、のではなく、8月一杯でできる範囲で抑える。9月以降はYakiBikiにとりかかるから。
YakiBikiにおいては、まだあくまでも目論見なんだけど・・・Xhwlayは画面遷移、というよりはバックエンドAPIをStateFull化するための仕掛けで使えれば、と考えている。XhwlayのView自体はまあ普通にHTML + Ajax UIで済ます予定なんだけど、やっぱり基本はバックエンドAPIをまずメインに仕上げたい。そのためにVirtualRecordという概念、というか仕掛けも実証・実装してみたいし。フロントエンドはこの先、いろいろなタイプが出てくるだろうから、HTML + Ajax UI はあくまでも、現行のWebブラウザをフロントエンドに用いることを想定している、デフォルト実装という事になるだろう。
別に、LL言語で自動でログイン・POSTするスクリプト組んだって良いわけだし。Javaでガリガリ専用のGUIアプリを作ったって良いんだし。最近であればAIRとか?になるのかな。
本音を言えば、SimpletestのWebテスト機能を使ったテストが楽になりそうだから、というのもある。
まあ、まだまだ先の話だけど・・・。なにしろ8月の土曜日、全部会社の手伝いで埋められた・・・。
ログイン・ログアウトの実装を考えていたとき。
「・・・しまった。setup-HOOKでLocationなどでリダイレクトしたとき、Flow制御全体をスキップする機能、実装してねぇ・・・。」
かくして、wipeout()が実装された。
setup-HOOKに、
function setup_check_login_redirect($hook, &$runner) { if ( !Foo_Bar::isLogined() ) { header("Location: http://...."); $runner->wipeout(); } }
とかをpushして使います。
ちょっとまとめてみます。
抑止力: wipeout() >> skipPage()
下の表の記号は次のような意味です。
○:制御メソッドの呼び出しにかかわらず、実行されます。 ×:制御メソッドを呼び出すことで、実行されません。 ▼:呼び出しポイント
制御メソッド→ | wipeout() | skipPage() | (Renderer無効化) |
---|---|---|---|
setup-HOOK | ▼ | ▼ | ○ |
Barrier | × | ▼ | ○ |
Guard | × | ▼ | ○ |
Event | × | ▼ | ○ |
Page | × | × | ▼(*1) |
Renderer | × | × | × |
terminate-HOOK | ○ | ○ | ○ |
以下余談、というか頭の中の妄想を踏まえて。
これで一通りlogin/logoutは固まったかな・・・。
結局、画面遷移の好みに応じて千差万別な形態がありうるわけで。
今のところ、ActorにAbstractを用意したり、同じフローでがりがり書いたり、
ログイン処理専用のフローを別に用意してsetupHOOKでリダイレクトかけたり、といろいろできる。
で、いろいろできるようにしておくのがフレームワークの仕事。
可能性、abilityだけは確保しておく。
実装を提供してそれを狭めてしまうのは、論外。
・・・ずいぶん風変わりなポリシーだけどね。でも、それがPokoXから続く、Xhwlayのポリシー。自由は、全て開発者の手に。フレームワークにより縛らない。
う~~ん・・・本末転倒。
現状のConfigのneedsBookmark()のIFはこうなっている。
function needsBookmark($page = null, $aci = "*")
で、$pageが省略された場合はStory全体のBookmark ON/OFFを取得し、$pageが指定された場合はページ単位のBookmark ON/OFFを取得できるようになっている。
が。実際のそのテストケースを作ろうとして。
・・・これ、要らなくね?
現実問題として、一つのStoryの中にBookmark ON/OFFが混ざることはあり得るのか?例えXhwlay側でサポートするとしても、本当にそんなStoryを作る場面があるのか?当初予定としては、例えばヘルプ画面ポップアップのようなものを想定していたが、それにしたってBookmarkOFFのヘルプ画面専用のstoryを作るのが普通じゃないか?
何よりも、BookmarkON/OFFの混ざったStoryって、激しくメンテナンス性が悪くないか?絶対に、あとあとFlowが追えなくなる。
というわけで、Xhwlay_Runnerレベルではもう、ページ単位のBookmark ON/OFFはサポートしない。どうしてもやりたければ、Xhwaly_Runnerをextendsして、コアを好きなように書き換えて下さい。という感じ。
まあ、Config側のIFは変更しない。Configの機能としては、純粋にまあ、あっても良いかなという感じなので。
そんなところ。
そしてようやく、な感じ。PartialBookmarkの見送りに助けられた。
小さな変更点として、Page/Event/Barrier/Guardの各種callbackを取得する為の _getCallback($params) 内で、
define('XHWLAY_RUNNER_HOOK_CLASSLOAD', "xhwlay_runner_classload");
で定義されるHOOKを呼ぶよう、修正した。Testには盛りこみ済。
一応現状は、デフォルトの _getCallback()は
"user_function" > "class" & "method"
の優先度でcallbackの有効性を判断している。classloadのHookを仕込むことにより、これらのパラメータに応じて動的にファイルをrequireできるようになる。
まあ、PokoXにあった
$POKOX_MODULE_AUTOLOAD_PATH
を好き勝手に実装してもらう為のマージン。
最近はPEAR形式のクラス名やディレクトリ構造を取ったりもするので、環境によって変わるだろうし・・・。
さて、これでベースコアは一応まとまった。普通のsessionベースでのサンプルと、ログイン/ログアウト込みのサンプルの準備に取りかかろう。
sessionを使わないのは・・・まあ、一応準備するか・・・。多分、あり得ないんだけど。だってBCID(Bookmark Container ID)自身がsessionIDになってしまうから。そうなると。・・・まあ、それはそれで無理矢理Cookie経由でやりとりさせて・・・って、それじゃsessionを使ってるのと変わらないし。
やっぱり、だめ・・・。Xhwlay_Runnerはやはりある程度拡張して使う事も意識している為、基底となるクラスでSingleton提供するのは、不味い。
ということで、getRunner()は削除。
で、結局、Page/Event/Guard/BarrierそれぞれのI/Fに
&$runner
が復活。しゃーないか・・・。
Xhwlay_Runnerのテストになると、あるパスを通す・関数を通すだけでも結構億劫になる。
・・・というよりは、一回のテストケース("testほげほげ"というメソッドになる)の中で、なるべく沢山のルートを潰そうとすると、訳分からなくなる。
"あそこで設定していたからこっちではこうなるはず"がかなり入り組んでくる為、却ってメンテナンス性が落ちる。
というわけで、あまり一回のテストケースであちこち潰そうとせず、一つのテストケースでは一つのポイントになるべく絞り込み、それ以外は、気にはなるけどぐっと抑えて思い切って無視するのが正しいかも知れない。
ということで、今はそのような感じでXhwlay_RunnerのEventモードを実装したり、テストケースを作ったりしている最中。
フレームワークのコアレベルになり、大分きつくなってきたな・・・。
ページ:アクションのマッピングという、従来のフレームワークの概念の延長線上でステートフルをサポートする、というXhwlayの当初目的。
・・・いろいろ考えてみたんだけど、どうも、意味が半減するような気がしてきた。
というのは、現時点でのXhwlayは実際にModelを動かすのはやはりページにマッピングされたアクション。&br;
で、その後 手動で Bookmarkのページを次に動かす必要がある。
これは・・・勿体ない、というか、 危ない。 Bookmark・・・正確にはアクションに引数で渡されてきた&$bookmarkに対して、
$bookmark->setPageName("次のページ名");
をプログラマが意識して呼ばないと、・・・逆にこれを呼び忘れると、CSRFが効いてしまう。
では逆に、これを呼んでいることを保証できるUnitTestツールなどを用意できるか、と言われれば、そこまでするリソースは持ち合わせていない。
つまり、せっかくのステートフルな仕組みが中途半端になってしまう。羊頭狗肉じゃないか。
こりゃまずい・・・というわけでいろいろあれこれ考えてみた結果、やっぱり、
Page -> (Event) -> Transit -> Page -> (Event) -> Transit -> Page -> ...
という、Piece-Flowも採用している、一般的なステートマシンの動き方を採用することになりました。
うわっConfig関連も全部UTしなおし。
で、じゃあ現状採用しているBarrierはどうするか・・・Guardとするか・・・なんだけど。
う~~ん・・・まあ・・・しても・・・いいか・・・?POST値とかGET値の入力チェック処理だけを綺麗にモジュール化したい、っていうのであれば、分けた方が良いんだよね。う~~ん・・・まぁ・・・HTML_QuickForm使う場合であれば、Formのビルダを別クラスにしておいて、validateだけするっていうのもありだし・・・。
うん、ちょっと面倒くさくなりそうだけど、将来的なわかりやすさから言えば、実装するに値する。
というか、Guardが無い場合、Event側で前頁に戻す処理を可能にしなければならない。・・・面倒なんだよな・・・。
あ、あと、transitすれども次のPageはInvokeせず。というパターンも考慮しておかないと。HTTP304でLocationさせるルート。
これは・・・Runnerに、escape()を用意すれば良いかな・・・。いや、EventHandlerがnullを返せば良い。
Configは最終的にはこんな感じになるだろう。
"page.aci" => array( "event" => array( "event1", "event2", "event3", ), ), "event" => array( "event1" => array( "guard" => array( "component" => "EventGuard_guard1.class.php", ), "component" => "EventAction_event1.class.php", "transit" => array( "error" => "page_error1", "success" => "page2", "invalid" => "page1", ), ), ), );
Transitが返すのはあくまでも文字列。で、Config側で文字列とページ名をマッピングする。aciは保持。
なんだかPieceっぽくなってきちゃったけど・・・まあ、いっか。一応この辺りまで分離することで、雛形の自動生成への道も開ける。
うん、これですっきりする。で、もしもLocationせずに、普通に遷移先のpageをinvokeして続行するとした場合、URLに"&_event=..."ってのこっちゃうので、二重POSTまたはDouble-Requestが走るけど、内部的にはすでにpage2に遷移しているので、page2のほうでの"event"にそのevent名が定義されていなければ当然何も起こらない、というだけの話。
これで、DataのCUD(Create/Update/Delete)に対するActionと、単なるR(Refer)とをきれいに分割し、また、FWレベルでもきれいに分離できるようになった・・・。また大分改造が入るけど、まあしょうがないな。
ただこれやると、単純なpage遷移が使えなくなる。あと、局所的なBookmark-OFFも使えなくなる。
まあ・・・その辺は、併用でも良いかもしれない。BookmarkがOFFになると、event志向ではページを動かせなくなるから。
今どのページで、というのは、BookmarkがOFFの時に限り、ユーザーランドで調整できても良いかもしれない。
あるいは"event"属性が未定義の場合。"next"で遷移させる、という手もある。
つまり"event"と"next"が指定可能で、"next"にはBookmark-OFFのページのみへ遷移可能、とか。いや、Bookmark-ONでも平気か。
$_eventが指定された場合は"event"に従い遷移し、"_page"が指定されたときは"next"に従い遷移する。
両方していされた場合は・・・どうしようかね。無効なパラメータ指定だから、No-Event, No-Actionで支障ないでしょう。
上手く組み合わせれば、局所的なBookmark-OFFも実現できるかもしれない・・・。
うん。大体まとまったな。単純なpage遷移のフォローも、"next"属性存続で路が残された。こんな感じで、良いんじゃない?
Guardも、Page遷移で利用できるようにしたいから・・・Configをまとめ直すと、こんな感じかな?
"page.aci" => array( "bookmark" => "off", "next" => array( "pageA" => "guard1", "pageB" => null, ), "event" => array( "event1" => "guard2", "event2" => "guard3", "event3" => "guard4", ), ), "guard" => array( "guard1" => array( "component" => "PageGuard_guard1.class.php" ), "guard2" => array( "component" => "EventGuard_guard2.class.php" ), ... ), "event" => array( "event1" => array( "component" => "EventAction_event1.class.php", "transit" => array( "error" => "page_error1", "success" => "page2", "invalid" => "page1", ), ), ), );
こんな感じか。