サーバーサイドで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 にデータを追加するコードを紹介します。

var newRec;

newRec = new me.store.recordType(obj, null);
me.store.add( newRec );

このように,recordType でレコードを作り,add メソッドで追加します。上記の例ではobjに追加したいレコードのデータが入っているという前提です。レコードの id プロパティが空の時に ExtJS はそれが追加されたレコードであると判断します。

サーバー側 PHP(xFrameworkPX)

次にサーバー側のコードを書いていきます。

ExtDirect コントローラー

.extdirect.php を webapp フォルダに作成します。

class extdirect extends xFrameworkPX_Controller_ExtDirect
{

    public $direct = array(
    'namespace' => 'Ext.remote'
    );
    public $modules = array(
    'employee' => array( 'conn' => 'default' )
    );

}

ネームスペースを設定して,利用するモジュール(employee)をuseしています。これだけで xFrameworkPX がいろいろと世話をしてくれるので, employee モジュールのメソッドを ExtDirect から利用可能になります。

employee モジュール

class employee extends xFrameworkPX_Model
{

    public $usetable = 'employee';

    // メソッドを記述

}

xFrameworkPX でのモジュールは,modules ディレクトリに配置します。

readData メソッド

データを読み出すための readData メソッドを実装します。

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
        );

    }

データベースから従業員データをとってきて,その一覧を返しています。返却するデータは最後の return 文のような形式で返します。

この中の items というキー名は任意ですが,このキー名を Store の root コンフィグにセットしなければなりません。他のキー名にした場合には,Store の root コンフィグにその名前をセットします。

deleteData メソッド

destroy アクションが発行された場合に実行されます。この場合,サーバに渡されるオブジェクトの items プロパティに削除すべきレコードの id が渡されます。削除するレコードが複数ある場合には items は配列になります。この例での items となっている要素ですが,この items というキーは前述の通り, root コンフィグに設定されている値になります。root コンフィグの値が違っていればこのキー名も変わります。(この点については他のメソッドでも同様です)

実際の deleteData メソッドのコードです。

<div>
public function deleteData( $pData )
{

    $data = $pData-&amp;amp;gt;items;
    if( ! is_array($data) ){
        $data = array($data);
    }

    $result = true;

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

}
</code></pre>

<p>    private function _deleteOne( $id )
    {</p>

<pre><code>    $where = array(
        'id = :id'
    );
    $bind = array(
        'id' =&amp;amp;gt; $id
    );
    $result = $this-&amp;amp;gt;delete(
        array(
            'where' =&amp;amp;gt; $where,
            'bind' =&amp;amp;gt; $bind
        )
    );
    return $result;

}
</code></pre>

<p>

サーバーに渡されるのは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 の場合はキーのフィールドと変更があったフィールドだけが渡されます。

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
            )
        );

    }

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

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

insertData メソッド

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

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;

    }

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

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