- 2008年11月24日 20:16
- ActionScript3.0 | CakePHP | PHP
AirのSWFファイルからPHPが動いているサーバーに接続する為には、AMFというフォーマットに従って通信を行う。
PHPのAMFライブラリとしては、AMFPHP が有名だけど、以下の記事によると、SabreAMF というライブラリがCakePHPに実装しやすいらしい。
実装方法としては、上記記事のタイトル通り、CakePHPのコンポーネントとして実装させる。
上記記事のコンポーネントを参考にもっと理解しやすいようにシンプルに書いてみたので参考にどうぞ。
VendorsディレクトリにSabreAMFを設置する
以下よりSabreAMFをダウンロードし、解凍後、ディレクトリ名をSabreAMFにリネームし[app/vendors]に設置する。
2008/11/24時点でのバージョンは、1.2.203
componentsディレクトリにsabre_amf.phpを設置する
以下のソースをコピーして、[app/controllers/components/sabre_amf.php]として設置する。
set_include_path(APP.'vendors' . PATH_SEPARATOR . get_include_path());
App::import('Vendor', 'SabreAMF_CallbackServer', array('file'=>'SabreAMF/CallbackServer.php'));
class SabreAmfComponent extends Object {
function startup(&$controller) {
if ($controller->action == 'gateway') {
global $_cakeController;
$_cakeController = $controller;
Configure::write('debug', 0);
// コールバックサーバーを立ち上げる
$controller->autoRender = false;
$server = new SabreAMF_CallbackServer();
$server->onInvokeService = array($this,'amfCallBack');
$server->exec();
exit;
}elseif(empty($controller->amfExclude) || !in_array($controller->action,$controller->amfExclude)){
exit();
}
}
function amfCallBack($service, $method, $data) {
global $_cakeController;
$res = null;
if ($_cakeController) {
if (strpos($method, "_") !== 0) { // _(アンダーバー)で始まるmethodはエラー。
if (method_exists($_cakeController, $method) && !in_array($_cakeController->action,$_cakeController->amfExclude)) {
// CakePHPのメソッドを呼び出せるように変換をかける。
$res = call_user_func_array( array( $_cakeController, $method ), $data );
} else {
$res = "not found action.";
}
} else {
$res = "invalid method name.";
}
} else {
$res = "not found controller.";
}
return $res;
}
}
コンポーネントのstartupメソッドで、CallbackServerを立ち上げ、
CallbackServerがリクエストを解析後、コールバックメソッドでCakePHPのメソッドを呼び出すという流れだ。
そうすると、mxml側からCakePHPのコントローラーを引数つきで呼び出せる。
コントローラーの設置例
以下のソースを[app/controllers/amfs_controller.php]として設置する
amfExclude = array('normal');
}
//これは通常表示できるアクション
function normal() {
$this->set("hoge", date("Y-m-d H:i:s"));
}
function gettext($message){
$ret = date("H:i:s")." ".$message;
return $ret; //各action で return した値が flashに返る。
}
//配列返却
function getarr($data) {
return $data;
}
}
?>
コントローラー側では、$componentsにSabreAmfを指定するだけで利用可能となる。
また、beforeFilterメソッドで$this->amfExcludeに配列で除外対象のアクションを指定するとAMFでは利用できず、
通常のアクションとして利用できるようになる。
$this->amfExclude = array('normal');
AIRアプリケーションを作成例
以下のコードを元にmxmlファイルを作成しコンパイルする。
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="240" height="408">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.utils.ArrayUtil;
import mx.collections.ArrayCollection;
import mx.rpc.events.*;
[Bindable]
private var myDataItem:ArrayCollection = new ArrayCollection;
private function sendMessage():void {
ro1.gettext(msg.text);
msg.text = "";
}
private function resultHandler1(e:ResultEvent):void {
log.text = e.result.toString() + "\n" + log.text;
}
private function resultHandler2(evt:ResultEvent):void {
myDataItem.addItem(evt.result);
}
private function faultHandler(evt:FaultEvent):void {
Alert.show("Fault: " + evt.fault + " Msg: " + evt.message);
}
]]>
</mx:Script>
<!--
<RemoteObject設定項目>
endpoint = "http://ホスト名/コントローラー名/gateway"
destination = "送信先名"(内容な任意だが必須)
result = "成功時の返信後処理"
fault = "失敗時の返信後処理"
gatewayファイルを設置した場合は、endpointでなく、sourceでクラスを指定する事もできる。
endopointなどをservices-config.xmlで設定する事もできる。
その場合、コンパイルオプションに、-services="services-config.xml"を追加する。
-->
<!-- 文字列読み込み例 -->
<mx:RemoteObject id="ro1"
endpoint = "http://localhost/amftest/amfs/gateway"
destination="amftest"
result="resultHandler1( event )"
fault="faultHandler( event )">
</mx:RemoteObject>
<mx:TextArea id="log" width="200" height="152" x="10.5" y="40"/>
<mx:TextInput id="msg" x="8.5" y="10"/>
<mx:Button label="send" click="sendMessage()" x="176.5" y="10"/>
<!-- 配列読み込み例 -->
<mx:RemoteObject id="ro2"
endpoint="http://amftest.localhost/amfs/gateway"
destination="amftest"
result="resultHandler2(event)"
fault="faultHandler(event)">
</mx:RemoteObject>
<mx:Button label="array load test" click="ro2.getarr({col1:'1',col2:'abc'})" x="10" y="360"/>
<mx:DataGrid id="myData" dataProvider="{myDataItem}" x="10" y="200">
<mx:columns>
<mx:DataGridColumn headerText="列 1" dataField="col1"/>
<mx:DataGridColumn headerText="列 2" dataField="col2"/>
</mx:columns>
</mx:DataGrid>
</mx:WindowedApplication>
mxml側の処理としては、URLのフルパスをRemoteObjectのendpointとし、その際のactionをgatewayとする仕様とした。
(例)http://localhost/コントローラー名/gateway
その代わり、通常サービスを指定するsorceは指定しない。
CakePHPの場合、dispatcherから呼び出されたコントローラーを操作できなくては、CakePHPの恩恵にあずかれない為、
gatewayを呼び出した際に、同時に呼び出されたコントローラーを処理対象のコントローラーとした方が処理効率がよいからだ。
そして、後はボタンのクリックイベントなどに、RemoteObject.action()という形式で実装する事でCakePHPのアクションを呼び出せる。
- Newer: CakePHP RC4出ました!
- Older: NetBeans6.5でCakePHPを使う
