前回は、
Piece_Unity 1.0.0から1.1.0へのアップグレード
先日Piece_
> pear.bat upgrade piece/piece_unity ... > pear.bat list -a INSTALLED PACKAGES, CHANNEL __URI: ================================== (no packages installed) INSTALLED PACKAGES, CHANNEL PEAR.PHP.NET: ========================================= PACKAGE VERSION STATE Archive_Tar 1.3.2 stable Cache_Lite 1.7.2 stable Console_Getopt 1.2.3 stable HTML_Template_Flexy 1.2.5 stable Net_URL 1.0.15 stable PEAR 1.6.1 stable Structures_Graph 1.0.2 stable INSTALLED PACKAGES, CHANNEL PEAR.PIECE-FRAMEWORK.COM: ===================================================== PACKAGE VERSION STATE Piece_Examples_Basics 1.0.0 stable Piece_Flow 1.13.0 stable Piece_Right 1.7.0 stable Piece_Unity 1.1.0 stable Piece_Unity_Component_Authentication 0.13.0 beta Piece_Unity_Component_Flexy 1.0.0 stable Piece_Unity_Component_NullByteAttackPreventation 1.0.0 stable Stagehand_FSM 1.9.0 stable INSTALLED PACKAGES, CHANNEL PECL.PHP.NET: ========================================= (no packages installed)
アップグレード完了後、
フロー定義ファイルの作成-エントリー一覧フロー
エントリポイントに着目し画面遷移設計を行った結果、
![エントリー一覧フローのステートチャート図 エントリー一覧フローのステートチャート図](/assets/images/dev/serial/01/piece/0005/thumb/TH400_01.png)
上記のステートチャート図は、
firstState: DisplayList
viewState:
- name: DisplayList
view: List
フロー定義ファイルは任意の場所に配置することができますが、
フロー定義ファイルのフォーマットにはYAML
firstState要素は、
viewState要素は、
なお、
エントリポイントの作成-エントリー一覧フロー
では、
![http://pieceblog/list.phpへのアクセス結果画面 http://pieceblog/list.phpへのアクセス結果画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_02.jpg)
おっと、
では、
<?php
error_reporting(E_ALL);
// ブロック1
require_once 'Piece/Unity.php';
require_once 'Piece/Unity/Error.php';
// ブロック2
Piece_Unity_Error::pushCallback(create_function('$error', 'var_dump($error); return ' . PEAR_ERRORSTACK_DIE . ';'));
// ブロック3
$base = dirname(__FILE__) . '/../webapp';
// ブロック4
ini_set('session.cookie_path', str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])));
session_save_path("$base/sessions");
// ブロック5
$unity = &new Piece_Unity("$base/config", "$base/cache");
// ブロック6
$unity->setConfiguration('Dispatcher_Continuation', 'flowName', 'EntryList');
$unity->setConfiguration('Renderer_Flexy', 'templateDir', "$base/templates/Entry");
$unity->setConfiguration('Renderer_Flexy', 'compileDir', "$base/compiled-templates/Entry");
// ブロック7
$unity->dispatch();
?>
上記のコードを解説します。
ブロック1では、
require_ onceによって必要なファイルのインクルードを行っています。 ブロック2では、
簡易的なエラーハンドラとしてvar_ dump()を使ったものを設定しています。独自のエラーハンドラを設定することで、 Piece Framework内のエラーを例外に変換することもできます。 ブロック3では、
Webアプリケーションのベースディレクトリを変数化しています。アプリケーションの配置先によって動作しなくなることがないように工夫を施しています。 ブロック4では、
session. cookie_ path設定を上書きし、 セッションデータの保存ディレクトリを変更しています。ブロック3と同様に、 アプリケーションの配置先によって動作しなくなることがないように工夫を施しています。 ブロック5では、
Piece_ Unity設定ファイルの配置先ディレクトリ及びそのキャッシュの配置先ディレクトリを引数にPiece_ Unityクラスをインスタンス化しています。 ブロック6では、
Piece_ Unity::setConfiguration()をコールすることによってエントリポイント固有の設定を行っています。プラグインが持つ各設定のデフォルト値やPiece_ Unity設定ファイルの設定はこのように上書きすることができます。このような動的な設定はダイナミックコンフィグレーションと呼ばれています。 ブロック7では、
Piece_ Unity::dispatch()をコールすることによってPiece_ Unityの実行環境を稼働させています。
では、
![http://pieceblog/list.phpへのアクセス結果画面 http://pieceblog/list.phpへのアクセス結果画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_03.jpg)
アクセスは成功しましたが、
Piece_Unity設定ファイルへのフロー定義の追加-エントリー一覧フロー
Piece_
...
- name: Dispatcher_Continuation
point:
- name: actionDirectory
type: configuration
value: ../webapp/actions
- name: cacheDirectory
type: configuration
value: ../webapp/cache/flows
- name: flowDefinitions
type: configuration
value:
- name: RegistrationWithNonExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: false
- name: RegistrationWithExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: RegistrationWithExclusiveModeAndAHAH
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: Authentication
file: ../webapp/config/flows/Authentication.yaml
isExclusive: true
- name: ProtectedResource
file: ../webapp/config/flows/ProtectedResource.yaml
isExclusive: false
- name: EntryList
file: ../webapp/config/flows/Entry/List.yaml
isExclusive: false
...
では、
![http://pieceblog/list.phpへのアクセス結果画面 http://pieceblog/list.phpへのアクセス結果画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_04.jpg)
フロー定義の設定を行ったにもかかわらず、
では、
![http://pieceblog/list.phpへのアクセス結果画面 http://pieceblog/list.phpへのアクセス結果画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_07.jpg)
ようやくまともなページが表示されました。しかし、
<h4 class="date-header">List</h4>
![http://pieceblog/list.phpへのアクセス結果画面 http://pieceblog/list.phpへのアクセス結果画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_05.jpg)
きちんと指定されたビューであるListのHTMLテンプレートが表示されたことがわかります。これでエントリー一覧フローはひとまず完成です。
新規エントリー入力フロー
続いて、
![新規エントリー入力フローのステートチャート図 新規エントリー入力フローのステートチャート図](/assets/images/dev/serial/01/piece/0005/thumb/TH400_06.png)
firstState: DisplayNew
lastState:
name: DisplayNewFinish
view: http://example.org/list.php
viewState:
- name: DisplayNew
view: New
transition:
- event: DisplayNewConfirmFromDisplayNew
nextState: DisplayNewConfirm
- name: DisplayNewConfirm
view: NewConfirm
transition:
- event: DisplayNewFinishFromDisplayNewConfirm
nextState: DisplayNewFinish
- event: DisplayNewFromDisplayNewConfirm
nextState: DisplayNew
このフローは、
transition要素は、
lastState要素は、
このフローは新規エントリー入力完了時にエントリー一覧画面に遷移する仕様のため、
<h4 class="date-header">New</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayNewConfirmFromDisplayNew">Create</a><p>
<h4 class="date-header">NewConfirm</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayNewFromDisplayNewConfirm">Back</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayNewFinishFromDisplayNewConfirm">Create</a><p>
HTMLテンプレートには遷移に対応したリンクを記述しています。フロー定義に基づいた動作を行うエントリポイント
<?php
error_reporting(E_ALL);
require_once 'Piece/Unity.php';
require_once 'Piece/Unity/Error.php';
Piece_Unity_Error::pushCallback(create_function('$error', 'var_dump($error); return ' . PEAR_ERRORSTACK_DIE . ';'));
$base = dirname(__FILE__) . '/../webapp';
ini_set('session.cookie_path', str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])));
session_save_path("$base/sessions");
$unity = &new Piece_Unity("$base/config", "$base/cache");
$unity->setConfiguration('Dispatcher_Continuation', 'flowName', 'EntryNew');
$unity->setConfiguration('Renderer_Flexy', 'templateDir', "$base/templates/Entry");
$unity->setConfiguration('Renderer_Flexy', 'compileDir', "$base/compiled-templates/Entry");
$unity->dispatch();
?>
...
- name: Dispatcher_Continuation
point:
- name: actionDirectory
type: configuration
value: ../webapp/actions
- name: cacheDirectory
type: configuration
value: ../webapp/cache/flows
- name: flowDefinitions
type: configuration
value:
- name: RegistrationWithNonExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: false
- name: RegistrationWithExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: RegistrationWithExclusiveModeAndAHAH
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: Authentication
file: ../webapp/config/flows/Authentication.yaml
isExclusive: true
- name: ProtectedResource
file: ../webapp/config/flows/ProtectedResource.yaml
isExclusive: false
- name: EntryList
file: ../webapp/config/flows/Entry/List.yaml
isExclusive: false
- name: EntryNew
file: ../webapp/config/flows/Entry/New.yaml
isExclusive: false
...
上記の準備が完了したら、
![新規エントリー入力画面 新規エントリー入力画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_08.jpg)
![新規エントリー入力確認画面 新規エントリー入力確認画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_09.jpg)
![新規エントリー入力完了画面 新規エントリー入力完了画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_10.jpg)
今度は最初から問題なく動作します。新規エントリー入力確認画面からCreateリンクをクリックすると先程作成したエントリー一覧画面が表示されます。これは、
エントリー編集フロー
続いて、
![新規エントリー入力完了画面 新規エントリー入力完了画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_11.png)
firstState: DisplayShow
lastState:
name: DisplayDeleteFinish
view: http://example.org/list.php
viewState:
- name: DisplayShow
view: Show
transition:
- event: DisplayEditFromDisplayShow
nextState: DisplayEdit
- event: DisplayDeleteConfirmViaDisplayShowFromDisplayShow
nextState: DisplayDeleteConfirmViaDisplayShow
- name: DisplayEdit
view: Edit
transition:
- event: DisplayEditConfirmFromDisplayEdit
nextState: DisplayEditConfirm
- event: DisplayDeleteConfirmViaDisplayEditFromDisplayEdit
nextState: DisplayDeleteConfirmViaDisplayEdit
- name: DisplayEditConfirm
view: EditConfirm
transition:
- event: DisplayShowFromDisplayEditConfirm
nextState: DisplayShow
- event: DisplayEditFromDisplayEditConfirm
nextState: DisplayEdit
- name: DisplayDeleteConfirmViaDisplayShow
view: DeleteConfirmViaDisplayShow
transition:
- event: DisplayDeleteFinishFromDisplayDeleteConfirmViaDisplayShow
nextState: DisplayDeleteFinish
- event: DisplayShowFromDisplayDeleteConfirmViaDisplayShow
nextState: DisplayShow
- name: DisplayDeleteConfirmViaDisplayEdit
view: DeleteConfirmViaDisplayEdit
transition:
- event: DisplayDeleteFinishFromDisplayDeleteConfirmViaDisplayEdit
nextState: DisplayDeleteFinish
- event: DisplayEditFromDisplayDeleteConfirmViaDisplayEdit
nextState: DisplayEdit
<h4 class="date-header">Show</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayEditFromDisplayShow">Edit</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayDeleteConfirmViaDisplayShowFromDisplayShow">Delete</a><p>
<h4 class="date-header">Edit</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayEditConfirmFromDisplayEdit">Update</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayDeleteConfirmViaDisplayEditFromDisplayEdit">Delete</a><p>
<h4 class="date-header">EditConfirm</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayEditFromDisplayEditConfirm">Back</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayShowFromDisplayEditConfirm">Update</a><p>
<h4 class="date-header">DeleteConfirmViaDisplayShow</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayShowFromDisplayDeleteConfirmViaDisplayShow">Back</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayDeleteFinishFromDisplayDeleteConfirmViaDisplayShow">Delete</a><p>
<h4 class="date-header">DeleteConfirmViaDisplayEdit</h4>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayEditFromDisplayDeleteConfirmViaDisplayEdit">Back</a><p>
<p><a href="{__scriptName}?{__flowExecutionTicketKey}={__flowExecutionTicket}&{__eventNameKey}=DisplayDeleteFinishFromDisplayDeleteConfirmViaDisplayEdit">Delete</a><p>
<?php
error_reporting(E_ALL);
if (file_exists(dirname(__FILE__) . '/../../imports')) {
set_include_path(dirname(__FILE__) . '/../../imports/spyc-0.2.5' . PATH_SEPARATOR .
dirname(__FILE__) . '/../../imports/pear'
);
}
require_once 'Piece/Unity.php';
require_once 'Piece/Unity/Error.php';
Piece_Unity_Error::pushCallback(create_function('$error', 'var_dump($error); return ' . PEAR_ERRORSTACK_DIE . ';'));
$base = dirname(__FILE__) . '/../webapp';
ini_set('session.cookie_path', str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])));
session_save_path("$base/sessions");
$unity = &new Piece_Unity("$base/config", "$base/cache");
$unity->setConfiguration('Dispatcher_Continuation', 'flowName', 'EntryEdit');
$unity->setConfiguration('Renderer_Flexy', 'templateDir', "$base/templates/Entry");
$unity->setConfiguration('Renderer_Flexy', 'compileDir', "$base/compiled-templates/Entry");
$unity->dispatch();
?>
...
- name: Dispatcher_Continuation
point:
- name: actionDirectory
type: configuration
value: ../webapp/actions
- name: cacheDirectory
type: configuration
value: ../webapp/cache/flows
- name: flowDefinitions
type: configuration
value:
- name: RegistrationWithNonExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: false
- name: RegistrationWithExclusiveMode
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: RegistrationWithExclusiveModeAndAHAH
file: ../webapp/config/flows/Registration.yaml
isExclusive: true
- name: Authentication
file: ../webapp/config/flows/Authentication.yaml
isExclusive: true
- name: ProtectedResource
file: ../webapp/config/flows/ProtectedResource.yaml
isExclusive: false
- name: EntryList
file: ../webapp/config/flows/Entry/List.yaml
isExclusive: false
- name: EntryNew
file: ../webapp/config/flows/Entry/New.yaml
isExclusive: false
- name: EntryEdit
file: ../webapp/config/flows/Entry/Edit.yaml
isExclusive: false
...
上記の準備が完了したら、
![エントリー参照画面 エントリー参照画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_12.jpg)
![エントリー編集画面 エントリー編集画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_13.jpg)
![エントリー編集確認画面 エントリー編集確認画面](/assets/images/dev/serial/01/piece/0005/thumb/TH800_14.jpg)
![エントリー削除確認画面1 エントリー削除確認画面1](/assets/images/dev/serial/01/piece/0005/thumb/TH800_16.jpg)
![エントリー削除確認画面2 エントリー削除確認画面2](/assets/images/dev/serial/01/piece/0005/thumb/TH800_15.jpg)
今度も最初から問題なく動作します。画面遷移図ではひとつだったエントリー削除確認画面をふたつの異なるステートにしたのは、
フローの実行の復元にフローの実行毎に発行されるチケットが必要なこと、
おわりに
これで画面遷移設計とフロー定義は完了です。これまでの作業で、
次回は、