サーバーサイドでDirectStoreの更新処理を書く

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-&amp;gt;items;
    if( ! is_array($data) ){
        $data = array($data);
    }

    $result = true;

    foreach( $data as $id ){
        $result = $result &amp;gt;&amp;gt; $this-&amp;gt;_deleteOne( $id );
    }
    return array(
        'success' =&amp;gt; $result,
        'items' =&amp;gt; $data
    );

}

    private function _deleteOne( $id ) {

    $where = array(
        'id = :id'
    );
    $bind = array(
        'id' =&amp;gt; $id
    );
    $result = $this-&amp;gt;delete(
        array(
            'where' =&amp;gt; $where,
            'bind' =&amp;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-&gt;items; if( ! is_array($data) ){ $data = array($data); } $result = true; foreach( $data as $rec ){ $result = $result &gt;&gt; $this-&gt;_updateOne( $rec ); } return array( ‘success’ =&gt; $result, ‘items’ =&gt; $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-&gt;update( array( ‘field’ =&gt; $fields, ‘value’ =&gt; $values, ‘where’ =&gt; $where, ‘bind’ =&gt; $rec ) ); } [/php]

このメソッドでは渡されたデータをひもといて update メソッドでレコードの更新をかけています。ここでも適切な値を返さなければなりません。やはり success プロパティと items プロパティが必要です。

ToDo:(items が id さえあればいいのかどうか確認。writeAllFields が false の場合も検証)

insertData メソッド

create アクションの時には,追加されたレコードのデータが渡されます。ここでも1レコードの場合は1件のオブジェクトが,複数レコードの場合はオブジェクトの配列が渡されます。戻り値も同様です。

[php] public function addData( $pData ) { $data = $pData-&gt;items; if( ! is_array($data) ){ $data = array($data); } $result = true; $rData = array(); foreach( $data as $rec ){ $rRec = (array)$rec; $id = $this-&gt;_addOne( $rRec ); $rRec[‘id’] = $id; $rData[] = $rRec; } return array( ‘success’ =&gt; $result, ‘items’ =&gt; $rData ); } private function _addOne( $rec ) { $fields = array( ‘name_kanji’, ‘name_kana’, ‘birth_date’ ); $values = array( ‘:name_kanji’, ‘:name_kana’, ‘:birth_date’ ); // 挿入実行 $result = $this-&gt;insert( array( ‘field’ =&gt; $fields, ‘value’ =&gt; $values, ‘bind’ =&gt; $rec ) ); $id = $this-&gt;lastId(); return $id; } [/php]

このメソッドでは,id フィールドは auto increment になっているという前提です。

ここのコードは,記事に書くためにちょっと短くしています。こちらのGitHubリポジトリですべてのソースをご覧になれます。