08.で DirectStore でのサーバー更新について調べましたが,それでは実際にサーバー側のルーチンはどう書いたらいいのでしょうか。ここでは,PHPとxFrameworkPXを使った場合を例示します。xFrameworkPXでは,ExtDirectコントローラーを使えば,モジュールのメソッドがそのままExtDirectで使えるという便利な機能があります。ここでは,そのモジュールのメソッドの記述例を示してExtDirectでのサーバー側の実装を示します。ただ,他のフレームワークを使った場合でも,API周りの処理に違いがあるとは思いますが,実際に処理するメソッド自体は大同小異だと思いますので,参考にはなると思います。
クライアント側 JavaScript
DirectStore の定義
次のような DirectStore を定義して,このストアの save メソッドをコールしたときに,ちゃんとサーバー側で更新がかかるようにします。例では autoSave を false にして自動保存されないようにしていますが,自動保存する場合でもほぼ同じです。この例では,保存するときの beforewrite イベントでローディングマスクを表示する処理を加えて, write イベントでマスクを解除しています。API コンフィグで指定しているのは,ExtDirect で公開されているメソッドです。Ext.remote というネームスペースに定義されるようになっています。CRUDそれぞれのメソッドが定義されています。
- Create = insertDataメソッド
- Read = readDataメソッド
- Update = updateData メソッド
- Delete = deleteData メソッド
Store へのレコードの追加
ここでは参考までに Store にデータを追加するコードを紹介します。
[js]
var newRec;
newRec = new me.store.recordType(obj, null);
me.store.add( newRec );
[/js]
このように,recordType でレコードを作り,add メソッドで追加します。上記の例ではobjに追加したいレコードのデータが入っているという前提です。レコードの id プロパティが空の時に ExtJS はそれが追加されたレコードであると判断します。
サーバー側 PHP(xFrameworkPX)
次にサーバー側のコードを書いていきます。
ExtDirect コントローラー
.extdirect.php を webapp フォルダに作成します。
[php]
class extdirect extends xFrameworkPX_Controller_ExtDirect
{
public $direct = array(
‘namespace’ => ‘Ext.remote’
);
public $modules = array(
‘employee’ => array( ‘conn’ => ‘default’ )
);
}
[/php]
ネームスペースを設定して,利用するモジュール(employee)をuseしています。これだけで xFrameworkPX がいろいろと世話をしてくれるので, employee モジュールのメソッドを ExtDirect から利用可能になります。
employee モジュール
[php]
class employee extends xFrameworkPX_Model
{
public $usetable = ‘employee’;
// メソッドを記述
}
[/php]
xFrameworkPX でのモジュールは,modules ディレクトリに配置します。
readData メソッド
データを読み出すための readData メソッドを実装します。
[php]
public function readData()
{
$fields = array(
‘id’,
‘name_kanji’,
‘name_kana’,
‘birth_date’
);
$order = array(
‘id’
);
$result = $this->get(
‘all’,
array(
‘fields’ => $fields,
‘order’ => $order
)
);
return array(
‘success’ => true,
‘total’ => count( $result ),
‘items’ => $result
);
}
[/php]
データベースから従業員データをとってきて,その一覧を返しています。返却するデータは最後の return 文のような形式で返します。
この中の items というキー名は任意ですが,このキー名を Store の root コンフィグにセットしなければなりません。他のキー名にした場合には,Store の root コンフィグにその名前をセットします。
deleteData メソッド
destroy アクションが発行された場合に実行されます。この場合,サーバに渡されるオブジェクトの items プロパティに削除すべきレコードの id が渡されます。削除するレコードが複数ある場合には items は配列になります。この例での items となっている要素ですが,この items というキーは前述の通り, root コンフィグに設定されている値になります。root コンフィグの値が違っていればこのキー名も変わります。(この点については他のメソッドでも同様です)
実際の deleteData メソッドのコードです。
<div>[php]
public function deleteData( $pData )
{
$data = $pData-&gt;items;
if( ! is_array($data) ){
$data = array($data);
}
$result = true;
foreach( $data as $id ){
$result = $result &gt;&gt; $this-&gt;_deleteOne( $id );
}
return array(
'success' =&gt; $result,
'items' =&gt; $data
);
}
private function _deleteOne( $id )
{
$where = array(
'id = :id'
);
$bind = array(
'id' =&gt; $id
);
$result = $this-&gt;delete(
array(
'where' =&gt; $where,
'bind' =&gt; $bind
)
);
return $result;
}
[/php]
サーバーに渡されるのはJSONのデータですが,PHPで受け取ったときには StdObject型のデータになります。配列の場合は配列で受け取れるのですが,オブジェクトの場合は StdObject のデータが渡されます。そこで最初に渡されたデータを配列にキャストしています。
Store の中で一つのレコードが削除された場合と,複数のレコードが削除された場合で,渡されるデータが違います。複数の場合のみデータは配列になっています。渡されたデータが配列であるかどうか判断して,配列でない場合は要素が一つの配列に格納してます。そしてその後,配列の各要素を引数にして _deleteOne メソッドをコールしています。
このメソッドの戻り値ですが,次のような内容を返す必要があります。
{ success: <flag>, items: [ {id : <id1>}, {id: <id2>}, ....] }
success プロパティには実行結果をセットします。true の場合は成功,false の場合は失敗ですね。成功した場合には,items (例によって root コンフィグの値によって変わります)プロパティに,削除されたレコードの id フィールドの値をプロパティに持つオブジェクトの配列をセットします。戻り値の方は1件の削除でも配列にする必要があります。_deleteOne メソッドの最後の方でこの1件ごとのオブジェクトを作成して返しています。deleteData メソッドの最後では,それらの結果の配列と success プロパティをつけて返しています。
渡されるオブジェクトと返すオブジェクトの形式は,update や insert でもほぼ同じですので,よく覚えておいてください。
updateData メソッド
update アクションの時には,更新されたレコードのデータが渡されます。ここでも1レコードの場合は1件のオブジェクトが,複数レコードの場合はオブジェクトの配列が渡されます。Store の writeAllFields コンフィグの値によって,渡されるオブジェクトの内容が変わります。この値が true の場合は,すべてのフィールドが渡されますし,この値が false の場合はキーのフィールドと変更があったフィールドだけが渡されます。
[php]
public function updateData( $pData )
{
$data = $pData->items;
if( ! is_array($data) ){
$data = array($data);
}
$result = true;
foreach( $data as $rec ){
$result = $result >> $this->_updateOne( $rec );
}
return array(
‘success’ => $result,
‘items’ => $data
);
}
private function _updateOne( $pRec )
{
$rec = (array)$pRec;
$fields = array(
‘name_kanji’,
‘name_kana’,
‘birth_date’
);
$values = array(
‘:name_kanji’,
‘:name_kana’,
‘:birth_date’
);
$where = array(
‘id = :id’
);
return $this->update(
array(
‘field’ => $fields,
‘value’ => $values,
‘where’ => $where,
‘bind’ => $rec
)
);
}
[/php]
このメソッドでは渡されたデータをひもといて update メソッドでレコードの更新をかけています。ここでも適切な値を返さなければなりません。やはり success プロパティと items プロパティが必要です。
ToDo:(items が id さえあればいいのかどうか確認。writeAllFields が false の場合も検証)
insertData メソッド
create アクションの時には,追加されたレコードのデータが渡されます。ここでも1レコードの場合は1件のオブジェクトが,複数レコードの場合はオブジェクトの配列が渡されます。戻り値も同様です。
[php]
public function addData( $pData )
{
$data = $pData->items;
if( ! is_array($data) ){
$data = array($data);
}
$result = true;
$rData = array();
foreach( $data as $rec ){
$rRec = (array)$rec;
$id = $this->_addOne( $rRec );
$rRec[‘id’] = $id;
$rData[] = $rRec;
}
return array(
‘success’ => $result,
‘items’ => $rData
);
}
private function _addOne( $rec )
{
$fields = array(
‘name_kanji’,
‘name_kana’,
‘birth_date’
);
$values = array(
‘:name_kanji’,
‘:name_kana’,
‘:birth_date’
);
// 挿入実行
$result = $this->insert(
array(
‘field’ => $fields,
‘value’ => $values,
‘bind’ => $rec
)
);
$id = $this->lastId();
return $id;
}
[/php]
このメソッドでは,id フィールドは auto increment になっているという前提です。
ここのコードは,記事に書くためにちょっと短くしています。こちらのGitHubリポジトリですべてのソースをご覧になれます。