アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

Flex4とsymfonyを連携させて遊んでみた。

最近仕事で毎日PHP4と格闘している橋本です、こんにちは。

さて、4繋がりということで、今日は先日β版がリリースされたばかりのFlashBuilder4を使って、
Flex4とsymfonyを連携させて遊んでみました。

Asialブログの購読者の方々の中に「symfonyって何??」って方はいらっしゃらないと思いますが、「Flexって何??」って方は中にはいらっしゃるかもしれないので、軽く説明。

Flexとは、Adobe社の提供するRIA(Rich Interface Application)開発のフレームワークです。
Adobeの得意分野であるFlashの技術をベースとしています。
インターフェースの作成には、MXMLというXMLを拡張した言語を用いて行います。
実行時には、MXMLファイルがswfファイルに変換され、クライアントのFlashPlayer上で実行されます。
Flexの開発キットのFlexSDKはAdobe社から配布されており無償でDL可能です。
(最新版:Adobe Flex4 SDK
また、有償ですが、FlashBuilder4(旧称 FlexBuilder)というEclipseベースのIDEを利用することも可能です。
(ちなみに、一個前のバージョンのFlexBuilder3は、学生の方ならば無料で利用することができます。こちら。学生さん、うらやましすぎです。)

今回はこのFlashBuilder4を使ってアプリ作成を進めていきたいと思います。


まず、FlashBuilder4をDL&インストールしましょう。

30日間は無料で使えます。

こちら

ちなみに、FlexBuilder3のライセンスを持っている場合は、β期間中は30日を超えても利用可能みたいです。)

次にsymfonyのインストールです。

と、言いたいところですが、既にsymfonyをお使いになっておられる方が多いかと思いますので、割愛。

今回はsymfony-1.2.8-DEVを使って進めていきます。


始める前に、そもそもどうやってFlashPHPでデータをやりとりするのかという話になるかと思いますので、軽く説明。

FlashPHPでデータのやりとりをする際には、AMF(ActionScript Messaging Format)というファイル形式を利用します。他にもXMLだったり、JSONだったりでやりとりすることも可能ですが、AMFはバイナリ形式でやりとりが可能なため、他の二つの方法よりも高速にデータのやりとりを行うことができます。

(少し古いデータですが、三つのデータ形式を利用した結果が載ってるページがありました。こちら

PHPでAMFを利用するためのライブラリとして主に、amfphp、WebOrb、SabreAMFの三つがありますが、今回はSabreAMFを利用します。

SabreAMFを使うのは、SabreAMFを利用したsymfonyのpluginが公開されていた、という単純な理由からです。

sfAmfPlugin

今回はこのpluginを使ってすすめていきたいと思います。

では、まず、symfonyプロジェクトを作成します。



symfony generate:project amf_sample
symfony generate:app frontend


次に、sfAmfPluginをインストールします。キャッシュのクリアもお忘れなく。



symfony plugin:install sfAmfPlugin
symfony cc


プラグインを使って、AMF-Serviceを作成します。



symfony amf:create-service --package=frontend.user Register
symfony cc


引数としてパッケージ名を渡していますが、これは渡しても渡さなくても大丈夫です。
パッケージ名を渡さなかった場合には、lib/services以下に、パッケージ名を渡した場合は、lib/services/パッケージ名にAMF-Serviceクラスのファイルが作成されます。

上記の例では、lib/services/frontend/user/RegisterServices.class.phpが作成されます。

次に、このサービスの中継役をするモジュールを作成します。

symfonyの場合は、モジュールとアクションを作ってやればOKです。



symfony generate:module amfgateway
symfony cc


apps/frontend/modules/amfgateway/actions/actions.class.php




class amfgatewayActions extends sfActions
{
  public function executeAmf(sfWebRequest $request) {
    $this->setLayout(false);

    $gateway = new sfAmfGateway();
    $response = sfContext::GetInstance()->getResponse();
    $response->setContent($gateway->service());
    return sfView::NONE;
  }
}



次に、サービスの中身を作っていきます。
といっても今日は簡単なことしかしません。
Flex側で取得した値をDoctrineに渡して保存するのみ。

DBはこんな感じの簡単なものを用意しました。



User:
  tableName: user
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name: string(255)
    email: string(255)
    phone: string(255)
    created_at: timestamp(25)
    updated_at: timestamp(25)
  actAs:
    Timestampable: { }


記述の仕方は普通にDoctrineを使用する場合と同じです。

lib/services/frontend/user/RegisterService.class.php



class RegisterService extends sfAmfService {
  // ユーザデータを保存する
  public function createUserData($user_data) {
    $user = new User();
    $user->fromArray($user_data);
    $user->save();

    return 'OK';
  }
}


次に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">
	<fx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.controls.Alert;
			import mx.events.CloseEvent;
			import mx.rpc.remoting.RemoteObject;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
				
			private function createUserData():void {
				var userData:Array = new Array();
				
				userData['name'] = userName.text;
				userData['email'] = email.text;
				userData['phone'] = phone.text;

                remote.addEventListener("result", function (e:ResultEvent):void {
                 	Alert.show(e.result.toString(), "Registrated!", null, null, function (e:CloseEvent):void {
						clearInputText();
                 	});
                });
                 
                remote.addEventListener("fault", function(event:FaultEvent):void {
                 	Alert.show(event.fault.toString(), "Error");
                });
                
                remote.createUserData(userData);
			}
			
			private function clearInputText():void {
				userName.text = "";
                email.text = "";
                phone.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="90.7" y="16.35" width="419" height="261" cornerRadius="0">
		<mx:Canvas label="register member" width="100%" height="100%" cornerRadius="0" alpha="1.0" borderStyle="none">
			<mx:Label x="50" y="27" text="Your name:"/>
			<s:TextInput x="149.25" y="25.25" id="userName"/>
			<mx:Label x="79.000015" y="67.65" text="email:"/>
			<s:TextInput x="149.25" y="64.65" id="email"/>
			<mx:Label x="75.000015" y="108.65" text="phone:"/>
			<s:TextInput x="149.25" y="111.65" id="phone"/>
			<s:Button x="231.3" y="170.65" label="clear" id="clear" click="clearInputText()"/>
			<s:Button x="118.3" y="170.65" label="create"  id="create" click="createUserData()"/>
		</mx:Canvas>
		<mx:Canvas label="show members" width="100%" height="100%">
			<mx:DataGrid x="15" y="10" height="265" width="453">
				<mx:columns>
					<mx:DataGridColumn headerText="ID" dataField="userId" width="50"/>
					<mx:DataGridColumn headerText="Name" dataField="userName" />
					<mx:DataGridColumn headerText="Email" dataField="email"/>
					<mx:DataGridColumn headerText="phone" dataField="phone"/>
				</mx:columns>
			</mx:DataGrid>
		</mx:Canvas>
	</mx:TabNavigator>
	
</s:Application>



RemoteObjectがサーバとのやりとりを行うオブジェクトです。
この中でも特に重要なのが、endpointとsourceです。
endpointは、さきほど作った中継役のモジュールのアクションを指定します。
sourceは、サービスをパッケージ名を含んだ形で指定します。

ようやく準備が整ったので、さっそく実行してみましょう。
実行するクライアントは、4つながりでsafari4を使用します。

実行時


登録完了時


FlashBuilderを使ってさくっと作っただけでしたが、一応ちゃんと動くものができました。

今回は登録だけでしたが、次回はDBからデータを持ってきて表示するところまでやってみたいと思います。

(本当は、今回でデータの取得と表示まで出来るようにしたかったのですが、Doctrineを使ったデータの取得部分ではまってしまったため延期です。すみません…。)