続・Flex4とsymfonyを連携させて遊んでみた。
屋内の寒さと、屋外の暑さの差で完全に夏バテ気味の橋本です、こんにちは。
早く秋がきてほしいですね。
秋いいよ、秋…。
はい。というわけで、みなさんも体調管理には気をつけてくださいませ。
さて、今回は前回に引き続き、Flex4 × Symfonyのお話です。
前回はsfAmfPluginの使い方と、データの保存処理について書きました。今回は引き続きデータの取得について書いていこうと思います。
(ちなみに、sfAmfPluginの2009/07/22現在の最新版はver.1.4.1です。前回使っていたver.1.3.0のバグがいくつか修正されているようなので、皆様こちらを使用しましょう。)
データの取得についても、前回と同様に、まずsymfony側でサービスのメソッドの作成をします。
とりあえず、前回の記事で作成した保存用のメソッドに加え、取得用のメソッドを作成します。
サービス
<?php
// lib/services/frontend/user/RegisterService.class.php
class RegisterService extends sfAmfService {
// ユーザデータを保存する
public function saveUserData($user_data) {
$user = new User();
$user->fromArray($user_data);
$user->save();
return 'OK';
}
// ユーザデータを取得する
/**
* @AmfReturnType("ArrayCollection")
*/
public function getUserData() {
$user_list = Doctrine::getTable('User')->getUserData();
return $user_list;
}
}
モデル
<?php
// lib/model/doctrine/UserTable.class.php
class UserTable extends Doctrine_Table
{
public function getUserData() {
$ret = array();
$rec = $this->createQuery('u')
->execute();
foreach ($rec as $user) {
$ret[] = array($user->id, $user->name, $user->email, $user->phone);
}
return $ret;
}
}
RegisterService.class.phpの保存用メソッド、getUserData()のコメント。
このコメントはアノテーションになっており、Flex側で受け取った際の戻り値の型を指定することができます。
今回は、戻り値をDataGridの中で使用するため、AllayCollection型で返します。
次にFlex側です。
ソースはこんな感じ。(またまた適当ですみません。)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024"
minHeight="768"
creationComplete="loadUserData()">
<fx:Script>
<![CDATA[
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.collections.ArrayCollection;
import mx.automation.IAutomationObject;
import mx.controls.Alert;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
[Bindable]
private var userDataList:ArrayCollection;
private function loadUserData():void {
// サービスの呼び出し
var token:AsyncToken = remote.getUserData();
// ResultEventとFaultEventの処理を登録
token.addResponder(new AsyncResponder(successLoadFunc, faultLoadFunc));
}
private function saveUserData():void {
// フォームで取得したデータを入れる配列
var data:Array = new Array();
data['name'] = nameForm.text;
data['email'] = emailForm.text;
data['phone'] = phoneForm.text;
// サービスの呼び出し
var token:AsyncToken = remote.saveUserData(data);
// ResultEventとFaultEventの処理を登録
token.addResponder(new AsyncResponder(successSaveFunc, faultSaveFunc));
}
private function successLoadFunc(e:ResultEvent,obj:Object = null):void {
// 明示的にキャストしないとエラーが出て、FlashBuilderさんがコンパイルしてくれません…
userDataList = ArrayCollection(e.result);
}
private function faultLoadFunc(e:FaultEvent,obj:Object=null):void{
Alert.show(e.toString(), "Error");
}
private function successSaveFunc(e:ResultEvent,obj:Object = null):void {
Alert.show(e.result.toString(), "Registerd");
// フォームをリセットして、データを再読み込みします。
resetUserData();
loadUserData();
}
private function faultSaveFunc(e:FaultEvent,obj:Object=null):void{
Alert.show(e.toString(), "Error");
}
private function resetUserData():void {
nameForm.text = "";
emailForm.text = "";
phoneForm.text = "";
}
]]>
</fx:Script>
<fx:Declarations>
<mx:RemoteObject
id="remote"
endpoint="http://amf_sample/amfgateway/amf"
source="frontend.user.RegisterService"
destination="hoge"
showBusyCursor="true"
/>
</fx:Declarations>
<mx:TabNavigator x="80" y="35" width="485" height="430">
<mx:Canvas label="save" width="100%" height="100%">
<s:Button x="80" y="270" label="Save" id="btnSaveUserData" click="saveUserData()"/>
<s:Button x="200" y="270" label="reset" id="btnResetUserData" click="resetUserData()"/>
<mx:Label x="50" y="40" text="Name"/>
<mx:Label x="50" y="120" text="Email"/>
<mx:Label x="50" y="200" text="Phone"/>
<s:TextInput x="150" y="35" id="nameForm" width="240"/>
<s:TextInput x="150" y="120" id="emailForm" width="240"/>
<s:TextInput x="150" y="200" id="phoneForm" width="240"/>
</mx:Canvas>
<mx:Canvas label="Load" width="100%" height="100%">
<mx:DataGrid x="20" y="20" height="340" width="450" dataProvider="{userDataList}">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="0"/>
<mx:DataGridColumn headerText="Name" dataField="1"/>
<mx:DataGridColumn headerText="Email" dataField="2"/>
<mx:DataGridColumn headerText="Phone" dataField="3"/>
</mx:columns>
</mx:DataGrid>
</mx:Canvas>
</mx:TabNavigator>
</s:Application>
タブナビゲータを使って、入力画面と表示画面を分けてあります。
Flex側のポイントはAsyncTokenクラスです。
RemoteObjectを使ってサーバのサービスを呼び出すと、ResultEventやFaultEventにレスポンスが返ってきます。そのレスポンスを受けるのがAsyncTokenクラスになります。(なんだか説明がわかりにくくてすみません。)
また、AsyncTokenのインスタンスには、addResponderメソッドを使ってレスポンダを登録することができます。レスポンダ(AsyncResponderクラス)には、レスポンスがresultの場合の処理と、faultの場合のメソッドをそれぞれ登録することができます。
サービスからの戻り値は、ResultEvent、FaultEventのresultというプロパティに格納されています。
その他は簡単です。サービスから取得したデータをDataGridのdataProviderに指定した変数(今回はArrayCollection型。Array型でも大丈夫です。)に入れてるだけ。
では、早速動かしてみます。
まずは、前回作った登録側から。
最初はデータがありません。
データを登録します。
保存成功。
データを確認。更新されています。やったね。
というわけで、二回にわたって書いてきたFlex4 x Symfony。よく分からないエラーに悩まされた日々もありましたが、結果的にデータの登録と取得が問題なく出来るようになりました。ここまで出来れば、あとは応用でいろいろと面白いことができそうです。
意外と簡単ですので、皆さんも是非やってみてください。
※ちなみに、前回の作成例 とコードが違うのは、間違って前回のデータを消してしまったためです。泣きました。皆さんも気をつけてください…。