yonet77的な雑記帳

日々思いついたネタなどを書き留めておきます

SalesforceでExtJS4を使ってみようか (1)

今日もForce.comネタです。すみません。

Salesforceの画面で、中を斜め読みでもしていると分かったりしますが、どうやらExtJSを色々利用しているみたいです。
このJavascriptライブラリ、最新版のExtJS4 ではMVCアーキテクチャを採用していて、なかなか使い勝手は良いと思います。他にも backbone.js など、様々なフレームワークがありますが、ExtJSを昔から使っています。なんとなくw
※ExtJS4の概要や基本的な使い方については、以下を参照下さい。。
Getting Started
MVC Architecture

そんなExtJS4を、Salesforce上で自分でも自由に使えないかなー・・と思って色々試してみました。
ExtJSSalesforce上で利用する上で、データをどうやってやり取りするか!?というところで悶え苦しんだあたりを今回は書き留めておこうと思います。

SalesforceのRemoteActionを利用するためのproxyを作成する

サーバ側(ココではSalesforce)からデータを参照したり、データを作成/更新/削除するのに、REST APIを利用するのは最も簡単で早く実装できる・・と思います。
Salesforceでは、REST APIを利用できるようになってはいますが、REST APIでアクセスする回数に制限(!!)があります。
「組織プロファイル」のAPI要求数で確認できます。
f:id:yonet77:20120219153629p:plain

※ちなみに、Sandbox環境では、5,000,000 に対して、運用環境では、5,000 もしくはユーザ数×1,000で大きい方が採用されます。
この数字、逆にして欲しいと願ってやまない今日この頃です。というか、そもそももっと増やして欲しい。

このAPI要求数、金出せば上限を増やすことはできるので、潤沢なAPI数が用意されているのであればREST APIで接続すれば良いと思います。
ただ、(資金が十分になくて)APIを好きなだけ使えない場合、どうすれば良いか・・・??
ということで、今回は「Remote Action」を使ってみました。

大雑把にいうと、

  1. Salesforce側でRemoteActionを用意しておく
  2. Javascript側から、SalesforceのRemoteAcitonを呼び出して、データの参照/作成/更新/削除を実行する

という感じです。

ただ、Javascriptに明るくないので、SalesforceのRemoteActionをコールするExtJS用のproxyを用意するのはどうすればッ・・・!?
※結論から言うと、見よう見真似で作ってみたので、一応動いてるけど、ちゃんと理解しないとどっかで痛い目みそうですねー・・というワケで、先に言っておこうと思います。
ぎゃふん (/++)/

ExtJSで近いProxyクラスは "Ext.data.proxy.Ajax" かなー・・というあたりで、これをコピーして適当(?)にちょちょいと書き換えました。。
(ホントは「ちょちょいと」なんて感じではなかったんですが、その四苦八苦の様子はそのうち整理して書けたら。。)
こんな感じです。↓

"remoteActionName" で、Salesforce側で用意してるRemoteActionを指定します。
"extraParams" で、RemoteActionに渡すパラメータをハッシュで指定します。

そいでもって、Salesforce側でRemoteActionを例えばこんな感じに定義します。

global with sharing class Con_RemoteAction {

    @RemoteAction
    global static List<sObject> doLoadData(Map<String, String> params){
        String query = params.containsKey('query') ? params.get('query') : '';
        return Database.query(query);
    }
}

元々、RemoteActionでは引数の数は自由に指定できます。

global with sharing class Sample {
    @RemoteAction
    global static void doTest(String str1, String str2, String str3){
        ....
    }
}

という感じに、例えば引数を3つ指定することもできます。
この場合、Javascriptからは

Sample.doTest('aaa','bbb','ccc', function(res,event){
    ....
}, {escape:true});

という感じに呼び出すことができます。
が、RemoteAction毎に引数の数がバラバラだと、Javascriptから呼び出すとき、どうやって1つのproxyクラスで対応するのか解決策が見つかりませんでした。。。
(RemoteAction毎にproxyクラスを作成する・・なんて面倒なことはやりたくないので。。)
そんなわけで、引数をハッシュとして持たせて、引数を常に1つとなるようにしてみました。

Javascript側で、こんな感じでproxyを作成します。

...
proxy:{
  type: 'remoteaction',
  remoteActionName: Con_RemoteAction.doLoadData,
  extraParams: {'query' : 'Select Id From Account'},
  reader: {
    type: 'json',
    model: '(ExtJS側で自前で作成したモデル名を指定)'
  }
},
...

そうすると、

  1. ExtJSのproxyが、Con_RemoteAction.doLoadData({'query' : 'Select Id From Account'}) をコールする
  2. Salesforce側で、変数queryに 'Select Id From Account' を格納する
  3. Salesforce側で、Database.query(query) を実行して結果を返す
  4. ExtJSのproxyで、受け取ったレコードを処理する(me.processResponse(...) とあるところ)

という流れになります。
Javascript側の処理の流れ(me.processResponse...)については....ちょっと追い切れてない、というか理解が追いついてないので省略(!?)しちゃってますが、そのうち整理できるといーなーと考えてます。。

GridPanelのDataStoreや、TreePanelのDataStoreに、上記のproxyを設定すればGrid / TreePanelにデータが表示されるかと。
Salesforceの画面に飽きてきたら、ExtJSのようなJavascriptフレームワークを使って全く違う画面を作ってみるのも一興かもしれません、というお話でした。