- 2022.03.28 Monday
- スポンサーサイト
-
一定期間更新がないため広告を表示しています
- | スポンサードリンク | - | | - | - | pookmark |
- 2011.02.13 Sunday
- 新時代をいくWEB開発会社としてやるべき : 「CakePHPを使ったFlexアプリのデータ通信方法」
-
またしても Adobe Developer Boxからのピックアップ-メモです。いま開発もこなすFlasherがやるべきWEB新開発手法だなとおもいました これです。新時代をいくWEB開発会社としてやるべき : 「CakePHPを使ったFlexアプリのデータ通信方法」
CakePHPのアツイ機能
- 複雑な設定なし
- データベースを設定するだけで、マジックが始まります。 - 簡単シンプル
- 名前を見たって、...Cakeだし。 - アクティブ、親切なコミュニティ
- 英語は #cakephp on IRC。日本語はhttp://cakephp.jp。 - 柔軟なライセンス
- MITライセンスで配布しています。 - Clean IP
- CakePHPの全コードはCakePHP開発チームによるものです。 - ベストプラクティス
- セキュリティ、認証、セッションハンドリング、その他をカバー。 - OO (オブジェクト(指向=オリエンテド))
- オブジェクト指向の熟練者でも、初心者でも快適に
Flex+PHPでアプリケーションを開発する時、サーバとのデータ通信部分の実装は手間がかかるものです。しかし、CakePHPを使えば簡単に実装することができます。本記事では、アドレス帳サンプルをもとに、CakePHPを使ったデータ通信方法を解説します。
サンプルデータ: sample.zip
CAKEPHPについて
CakePHPは、Ruby On Railsの影響を強く受けたフレームワークで、MVCやActiveRecord形式のO/Rマッピングといった特徴を持っています。CakePHPを使えば効率的に作業を進めることができ、短期間での開発が可能です。
FlexとPHPを用いたデータ通信方法には、FlexのRemoteObjectによる通信と、REST(XML)による通信の2通りがあります。RemoteObject通信では、AMF3(Action Message Format3)を使用することができます。CakePHPには、通信データをAMF形式で出力するためのライブラリがあります。以下は、その代表的なライブラリです。
- SabreAMF
- CakeSWXPHP
- CpAMF
- CakeAMFPHP
本記事では、この中から簡単に実装可能なCakeSWXPHPを使用して説明します。
CAKEPHPとCAKESWXPHPのインストール
CakePHPは最新バージョン1.3.xを使用します。CakePHPのインストール方法については、CakePHPのサイトを参考にして下さい。
CakePHPのインストールが完了したら、続いてCakeSWXPHPをインストールします。以下のサイトからCakeSWXPHPをダウンロードしてください。CakeSWXPHPは、CakePHPのバージョンごとに異なるダウンロードファイル(1.1.x向けと1.2.x向け)が用意されています。本記事ではCakePHP 1.3.xですが、1.2.x向けのCakeSWXPHPを使用することができます。
http://blog.aboutme.be/cakeswxphp/
ダウンロードしたCakeSWXPHPを解凍すると、フォルダ内に以下のディレクトリがあります。
app/
vendors/これらのディレクトリを、CakePHPのappディレクトリとvendersディレクトリにそれぞれ上書きします。
次に、このままでは日本語を扱った際に文字化けが起きるので、文字コードに関する記述を変更します。「app/webroot/amf.php」ファイルの34行目付近に、PHPの文字コードとMySQLの文字コードに関する記述があります。今回、PHPの文字コードとMySQLの文字コードをUTF-8にしているので、以下のように変更します。
<変更前>
$gateway->setCharsetHandler('utf8_decode','ISO-8859-1' ,'ISO-8859-1');
↓
<変更後>
$gateway->setCharsetHandler('utf8_decode','UTF-8' ,'UTF-8');
アドレス帳サンプルの概要
CakePHPとCakeSWSPHPを用いたシステムのサンプルとして、アドレス帳を作成します。
FlexとPHPでデータ通信を行う場合、「データベースからデータを取得して、XMLまたはAMF3で渡す」といったPHPプログラムの作成が必要になります。データ表示部分をFlexで作成し、CakePHPでデータ取得用のコントローラとモデルを作成します。以下は、Flexで作成するアドレス帳の表示部分です。左カラムがAMFデータ用、右カラムがXMLデータ用で、各カラムの下にある[データ取得]ボタンをクリックすると各データを取得します。AMFデータの取得にはRemoteObjectを使用し、XMLデータの取得にはHTTPServiceを使用します。なお、取得したデータはDataGridで表示させます。
アドレス帳のデータの作成
データベースサーバはMySQLを使用し、アクセス権限を以下のように設定します。
ユーザ名 root パスワード 123456 データベース amfsample アドレス帳のデータを格納するテーブル「address」を作成してデータを格納します。
CREATE TABLE IF NOT EXISTS `address` (
`id` int(11) NOT NULL,
`name` varchar(150) collate utf8_unicode_ci NOT NULL,
`address` varchar(255) collate utf8_unicode_ci NOT NULL,
`tel` varchar(13) collate utf8_unicode_ci NOT NULL,
`remarks` text collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;今回作成するサンプルはデータの取得部分のみですので、テスト用データはサンプル内のAMFSample/SQL/address.sqlにあるデータ挿入文を実行してください。
CAKEPHP側のコード作成
まず、先ほど作成したデータベースへアクセスするための設定をapp/config/database.php に記述します。
class DATABASE_CONFIG {
var $default = array(
'driver' => 'mysql', //使用するデータベースサーバ
'persistent' => false, //持続的接続
'host' => 'localhost', //データベースサーバを設置しているホスト名
'login' => 'root', //データベースサーバにアクセスするユーザ名
'password' => '123456', //データベースサーバにアクセスするパスワード
'database' => 'amfsample ',//使用するデータベース名
'prefix' => '', //接頭語
'encoding' => 'utf8' //文字エンコーディング
);
}作成したデータベースのテーブルに対してモデルとコントローラを作成して、それぞれ指定されたディレクトリに置きます。
モデル app/models コントローラ app/controllers ビュー app/views モデルの作成
以下は、モデルのPHPコードです。
app/models/address.php
class AddressesController extends AppController {
var $name = 'Addresses'; // コントローラ名
var $helpers = array( 'Xml'); // ヘルパー
/**
* 検索結果取得用メソッド
* @param $page 取得するページ
* @param $count 取得件数
* @return 検索結果の連想配列
*/
function get_amf( $page = 0 , $count = 20 ) {
return $this -> Address -> find(
'all' ,
array('limit'=> $count , 'offset' => $count*$page ) );
}
/**
* 検索結果取得用メソッド(XMLで出力)
* @param $page 取得するページ
* @param $count 取得件数
*/
function get_xml( $page = 0 , $count = 20 ) {
$this->set( 'data',$this -> Address -> find(
'all' ,
array('limit'=> $count , 'offset' => $count*$page ) ) );
$this -> layout = 'xml';
}
}【AMF用】
コントローラの中で、以下の部分がAMF用のコードです。ActionScript から直接アクセスすることができるCakePHPのコントローラ内のメソッドを定義しています。ActionScript は、このメソッドの戻り値を取得できます。/**
* 検索結果取得用メソッド
* @param $page 取得するページ
* @param $count 取得件数
* @return 検索結果の連想配列
*/
function get_amf( $page = 0 , $count = 20 ) {
return $this -> Address -> find(
'all' ,
array('limit'=> $count , 'offset' => $count*$page ) );
}【XML用】
コントローラの中で、以下の部分がXML用のコードです。CakePHP には、ビューの処理を効率化するために「ヘルパー」という機能があります。/**
* 検索結果取得用メソッド(XMLで出力)
* @param $page 取得するページ
* @param $count 取得件数
*/
function get_xml( $page = 0 , $count = 20 ) {
$this->set( 'data',$this -> Address -> find(
'all' ,
array('limit'=> $count , 'offset' => $count*$page ) ) );
$this -> layout = 'xml';
}ビューのdata 変数に検索結果を割り当てて、出力する際に使用するレイアウト名(ここでは「xml」)を定義します。取得した結果をXMLに変換するには、XMLヘルパーを設定します。
XMLヘルパーを使用するには、コントローラ内の$helpersプロパティに以下のように記述します。var $helpers = array( 'Xml');
XML用レイアウトファイルの作成
コントローラで「$this -> layout = 'xml';」とレイアウト名を「xml 」と定義したので、xml.ctpファイルをレイアウトディレクトリに作成します。
app/views/layouts/xml.ctp
<?php echo $this->Xml->header(); // XML ヘッダー出力 ?>
<?php echo $content_for_layout; // コンテンツ出力 ?>ビューの作成
コントローラのメソッドに対応するディレクトリをビューディレクトりに作成します。address コントローラの get_xml メソッドのビューを作成します。
app/views/addresses/get_xml.ctp
<addresses>
<?php
//data変数をXMLヘルパーのserializeメソッドで出力
echo $xml->serialize($data);
?>
</addresses>FLEX側のコード作成
次にFlexのコードを作成します。Sample.mxml、AmfSample.mxml、XmlSample.mxmlの3つのファイルを作成します。Sample.mxmlがアプリケーションファイルで、AMF用サンプルのAmfSample.mxmlとXML用サンプルのXmlSample.mxmlはコンポーネント化します。
Sample.mxml
以下は、Sample.mxmlのMXMLコードです。
FlexSample/src/Sample.mxml
<?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/mx"
minWidth="955" minHeight="600"
xmlns:ns1="*">
<ns1:AmfSample x="10" y="10" />
<ns1:XmlSample x="555" y="10" />
</s:Application>AmfSample.mxml
以下は、AmfSample.mxmlのMXMLコードです。
FlexSample/src/AmfSample.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="600" height="600">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Declarations>
<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
<s:RemoteObject
id="remote"
endpoint="http://localhost/AMFSample/amf.php"
destination="cakeSWXphp"
source="AddressesController"
result="handleResult(event)"
/>
</fx:Declarations>
<s:Label x="19" y="7" text="AMFサンプル" fontSize="20"/>
<mx:DataGrid x="19" y="30" id="adg1" dataProvider="{addresses}" height="500">
<mx:columns>
<mx:DataGridColumn headerText="列 1" dataField="Address.id"/>
<mx:DataGridColumn headerText="列 2" dataField="Address.name"/>
<mx:DataGridColumn headerText="列 3" dataField="Address.address"/>
<mx:DataGridColumn headerText="列 4" dataField="Address.tel"/>
<mx:DataGridColumn headerText="列 5" dataField="Address.remarks"/>
</mx:columns>
</mx:DataGrid>
<s:Button x="441" y="550" label="データ取得" id="btn" click="onClickBtn()"/>
<s:Label x="6" y="559" text="取得時間"/>
<s:Label x="73" y="560" text="{time}ミリ秒"/>
<s:TextInput x="305" y="549" id="sCount" restrict="[0-9]" imeMode="ALPHANUMERIC_HALF"/>
<s:Label x="245" y="559" text="取得件数"/>
<fx:Script>
<![CDATA[
import flash.utils.getTimer;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent;
[Bindable]
private var addresses:Array;
[Bindable]
private var time:Number;
private var sTime:Number;
/**
* 結果の取得
*/
private function handleResult( event:ResultEvent ):void{
time = getTimer() - sTime;
addresses = event.result as Array;
}
/**
* ボタンクリック時の動作を定義
*/
private function onClickBtn():void{
sTime = getTimer(); //時間の計測
var count:int;
if( sCount.text != ''){
count = parseInt( sCount.text ); //データの取得件数を設定
}
else{
count = 20;
}
remote.get_amf( 0,count ); //リモートのメソッドの実行
}
]]>
</fx:Script>
</s:Group>コードのポイントを解説していきましょう。RemoteObjectを使用すると、サーバ側のメソッドを直接コールすることができます。RemoteObjectを使用するため、MXMLで以下のように記述します。
Endpoint CakePHPのディレクトリ/webroot/amf.phpのURLを指定します。 Destination 何でも良いので、記述が必要です。 Source コントローラのファイル名を記述します。 Result 結果を受け取った時に実行するメソッドを記述します。 ボタンクリック時に、「remote.get_amf(0,20)」のようにCakePHPに記述したメソッドをそのまま実行できます。
private function onClickBtn():void{
sTime = getTimer(); //時間の計測
var count:int;
if( sCount.text != ''){
count = parseInt( sCount.text ); //データの取得件数を設定
}
else{
count = 20;
}
remote.get_amf( 0,count ); //リモートのメソッドの実行
}正常に結果が返るとresultイベントが発生して、指定されたメソッド(handleResult)を実行します。
[Bindable]
private var addresses:Array;
…
private function handleResult( event:ResultEvent ):void{
time = getTimer() - sTime;
addresses = event.result as Array;
}取得したアドレスデータを表示するため、DataGridコンポーネントを使用します。
<mx:DataGrid x="19" y="30" id="adg1" dataProvider="{addresses}" height="500">
<mx:columns>
<mx:DataGridColumn headerText="列 1" dataField="Address.id"/>
<mx:DataGridColumn headerText="列 2" dataField="Address.name"/>
<mx:DataGridColumn headerText="列 3" dataField="Address.address"/>
<mx:DataGridColumn headerText="列 4" dataField="Address.tel"/>
<mx:DataGridColumn headerText="列 5" dataField="Address.remarks"/>
</mx:columns>
</mx:DataGrid>XmlSample.mxml
以下は、XmlSample.mxmlのMXMLコードです。
FlexSample/src/XmlSample.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="600" height="600">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Declarations>
<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
<s:HTTPService
id="service"
result="handleResult(event)"
url="http://localhost/AMFSample/addresses/get_xml/{page}/{viewCount}"
resultFormat="e4x">
</s:HTTPService>
</fx:Declarations>
<s:Label x="19" y="7" text="XMLサンプル" fontSize="20"/>
<mx:DataGrid x="19" y="30" id="adg1" dataProvider="{addresses}" height="500">
<mx:columns>
<mx:DataGridColumn headerText="列 1" dataField="@id"/>
<mx:DataGridColumn headerText="列 2" dataField="@name"/>
<mx:DataGridColumn headerText="列 3" dataField="@address"/>
<mx:DataGridColumn headerText="列 4" dataField="@tel"/>
<mx:DataGridColumn headerText="列 5" dataField="@remarks"/>
</mx:columns>
</mx:DataGrid>
<s:Button x="441" y="550" label="データ取得" id="btn" click="onClickBtn()"/>
<s:Label x="6" y="559" text="取得時間"/>
<s:Label x="73" y="560" text="{time}ミリ秒"/>
<s:TextInput x="305" y="549" id="sCount" restrict="[0-9]" imeMode="ALPHANUMERIC_HALF"/>
<s:Label x="245" y="559" text="取得件数"/>
<fx:Script>
<![CDATA[
import flash.utils.getTimer;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent;
//アドレス一覧のデータ
[Bindable]
private var addresses:XMLList;
//表示件数
[Bindable]
private var viewCount:int = 20;
//表示ページ番号
[Bindable]
private var page:int = 0;
//計測時間
[Bindable]
private var time:Number;
//開始時間
private var sTime:Number;
/**
* 結果の取得
*/
private function handleResult( event:ResultEvent ):void{
time = getTimer() - sTime; //時間の計測
//取得したデータを設定
addresses = (event.result as XML).children();
}
/**
* ボタンクリック時の動作を定義
*/
private function onClickBtn():void{
sTime = getTimer(); // 時間の計測
if( sCount.text != "" ){
//取得件数を設定
viewCount = parseInt( sCount.text );
}
service.send();
}
]]>
</fx:Script>
</s:Group>コードのポイントを解説していきましょう。HttpServiceを使用して、XMLを取得する場合のコードを見ていきます。
<s:HTTPService
id="service"
result="handleResult(event)"
url="http://localhost/AMFSample/addresses/get_xml/{page}/{viewCount}"
resultFormat="e4x">
</s:HTTPService>RemoteObject と同様に、ボタンクリック時にHTTPServiceのSendメソッドでリクエストが送信されます。
private function onClickBtn():void{
sTime = getTimer(); // 時間の計測
if( sCount.text != "" ){
//取得件数を設定
viewCount = parseInt( sCount.text );
}
service.send();
}正常に結果が返ると、resultイベントが発生し、指定されたメソッド(handleResult)を実行します。
[Bindable]
private var addresses:XMLList;
…
private function handleResult( event:ResultEvent ):void{
time = getTimer() - sTime; //時間の計測
//取得したデータを設定
addresses = (event.result as XML).children();
}RemoteObject と同様に、取得したアドレスデータを表示するため、DataGridコンポーネントを使用します。
<mx:DataGrid x="19" y="30" id="adg1" dataProvider="{addresses}" height="500">
<mx:columns>
<mx:DataGridColumn headerText="列 1" dataField="Address.id"/>
<mx:DataGridColumn headerText="列 2" dataField="Address.name"/>
<mx:DataGridColumn headerText="列 3" dataField="Address.address"/>
<mx:DataGridColumn headerText="列 4" dataField="Address.tel"/>
<mx:DataGridColumn headerText="列 5" dataField="Address.remarks"/>
</mx:columns>
</mx:DataGrid>EST(XML)とAMFの速度比較
アドレス帳のデータをHTTPServiceによるXMLを使用したREST通信と、RemoteObjectを使用したAMF3の通信の速度について比 較してみましょう。10件、100件、1000件、10000件でそれぞれ10回接続した場合の平均値で比較することにします(Flexアプリケーション でリクエストを送信してから、結果を取得するまでのミリ秒数)。処理時間は、以下の環境で計測しています。
- CakePHP 1.3.2
- PHP 5.2.6
- Flash Player 10.1
- Flash Builder 4
速度比較結果
データ件数 AMF XML 10件の場合 235ミリ秒 215ミリ秒 100件の場合 276ミリ秒 265ミリ秒 1000件の場合 463ミリ秒 842ミリ秒 10000件の場合 2221ミリ秒 7391ミリ秒 結果を見ると、取得するデータが少ない場合、XMLの方が若干速いことが分かります。また、情報量が増えるにしたがってAMFの方が速いことが分かりま す。比較的データ量が少ない場合やデータ量が固定されている場合はXMLの方が有効で、データ量が多くなる場合やデータ構造がXMLでは複雑になる場合は AMFの方が有効だと思います。
最後に
本記事では、FlexとCakePHPによるデータ通信の方法について紹介しました。これによりCakePHP で開発されたWebアプリケーションを、Flexで実現する際にデータ通信方式をデータ量に応じて、選定できる基準になると思います。
著者について
積 祐二 さん
株式会社ヒューマンオークCakePHPとFlash Builderの使い手。主にCakePHPを用いたWebアプリケーションの開発やFlash Builderとの連携の案件に従事。
- 複雑な設定なし
- | whaison | CakePHP | 03:05 | comments(0) | trackbacks(0) | pookmark |