XPages SSJSで文字列から関数を動的に呼び出す方法
文字列から動的に関数を呼び出したいケースとは?
関数を文字列から動的に関数を呼び出したいケースってどんな時でしょうか? 例えばHTML GET/POSTメソッドのパラメーター値によって呼び出す関数を変えたい場合などが想定されます。
以下の例では、「http://mydomain.com/ApplyFuncXAgent.xsp?func=callMe」というような呼び出しに対してクライアントサイドJavascript(CSjS)でコールする関数を変更するというコードになります。
これを簡略化して文字列から動的に関数を呼び出したい場合、CSJSでは以下のような書き方ができます。
windowオブジェクトに登録されている関数オブジェクトを取得し関数としてコールしています。しかしながらXPagesのサーバーサイドJavascript(SSJS)ではwindowオブジェクトがありませんので別の方法で関数を呼び出してやる必要があります。
(1)windowの代わりにthisを使用する方法
(2)eval()を利用する方法
(1),(2)どちらでも同じ結果を得ることができます。
パラメーターを渡したい場合はcall()もしくはapply()を使用
SSJSでも文字列から直接関数として呼び出す方法は分かりましたが、次はその関数に引数を与えたい場合にどうするか。この方法はCSJSと同じになります。
例えば、「http://mydomain.com/ApplyFuncXAgent.xsp?func=callMe&args=aa,bb」というようにURLパラメータに[args=aa,bb]を追加して引数も渡す方法を想定します。この場合、以下のコードのようにcall()、もしくはapply()を利用してやることでパラメータを渡すことが可能になります。
apply()の場合はcall()の時の引数をカンマ区切りで指定するのではなく、第2引数にArrayとして指定してやります。
XAgentと組み合わせたサンプル
今回自分が必要であったシチュエーションはAJAXによる非同期通信でビューの値をJSON形式で取得するための汎用的なロジックを作りたかったからでした。以下のサンプルコードはXAgentになっており関数名と引数値をURLパラメータで渡すことによって呼び出し関数を変えて目的のJSONの値を返すようになっています。
想定しているURLの呼び出しは「http://mydomain.com/hoge.nsf/ApplyFuncXAgent.xsp?func=testFunc&args=aa,bb」などです。
上記XAgentから呼び出されているcallFuncByString()を含んだxpCommon.jssのサンプルコードです
複数のビューのJSON値を非同期通信で取得する毎にXAgentを用意しなくて済むといのがこの汎用化コードの利点ですが、関数を動的に呼び出すことそのものはデバッグがしづらくなるという欠点もあるため使用には慎重になったほうがいいケースもあると思います。
※セキュリティーの観点からこのXAgentをそのまま使うとSSJSの標準関数を含む幾多の関数を呼び出すことが可能になるので危険です。実際には機能制限をするなどして意図した関数以外を呼び出されないように注意を払ってください。
[CakePHP] JSON出力時にstring型をint型に戻す
久々のブログ、今回はCakePHPでJSON出力をするときにInteger型、String型に型変換して出力する方法について書きます。 (あ、今回も他力本願、満載)
まず、CakePHPでJSON出力をする為には
Controllerで
$yourJsonObect= $this->YourModel->find('all'); $this->set('yourJsonObect', $yourJsonObect);
としてやり
Viewで
<?php echo $javascript->object($yourJsonObect); ?>
としてやれば簡単に実現できます。
出力されるコードは以下のようになります。
[{"YourModel":{"id":"10060","foreign_id":"1","short_description":"Short Desc Test.","long_description":"Long Desc Test"}, {} ..... )]
これで、殆ど場合は問題ないのですが、データベース上でIntegerで持っているスキーマ(id, foreign_idなど)も全てString型として出力されます。
もし、JSONデータを受け取る側が厳密にInteger型、String型を区別して受け取りたい場合などに以下の方法でスマートに解決できたので紹介します。
余談ですが、自分の場合は、iPhone開発において、JSONデータをウェブサーバーから受け取り、Core DataにInsertする時に、iPhone側で型チェックや型変換をさせたくなかったので、サーバー側で吸収してしまおうという経緯がありました。
参考にしたサイトはこちらです。
CakePHPのmodelの結果配列でstring型をint型に戻す。
CakePHPでmodel::findなどの関数で結果配列を取得したときに、データベースではint型の値string型として返って来ます。
今回は、flashにjson出力でデータを渡したかったので、別に文字列型のまま渡しても問題ないのかもしれないけど、なんか気持ち悪い。
それに例えばよくある、intの0,1をフラグと扱って if (flag) {.... }なんて書いたらマズいんじゃないかと思うので、settypeで型変換を行う方法。
モデルの親クラスで、Findで取得したデータ(デフォルトは全てString)をデータベースのTypeを参照して、型変換を行っています。
app_model.phpにafterFind()オーバーライド関数を追加してやるだけ。
class AppModel extends Model{ public function afterFind($results, $primary = false) { parent::afterFind($results, $primary); $columnTypes = $this->getColumnTypes(); foreach($results as $index => $result) { foreach($columnTypes as $field => $columnType) { if($columnType == 'integer') { if(isset($results[$index][$this->name][$field])) { settype($results[$index][$this->name][$field], 'integer'); } } } } return $results; } }
これで全てのモデルが自動変換されるようになりました。 感激~
変換後のJSON出力を見ると以下のようになります。
[{"YourModel":{"id":10060,"foreign_id":1,"short_description":"Short Desc Test.","long_description":"Long Desc Test"}, {} ..... )]
Integer型の数字の部分からダブルクォーテーションが消えました。
めでたしめでたし。