[CakePHP] JavascriptHelper::object() オプションはJSON関数の有無に左右される

  • このエントリーをはてなブックマークに追加

JSON関数が有効なPHP環境ではJavascirptヘルパーのobjectメソッドのstringKeysquoteKeysqが効かなくなります。
これは良いのか?って思う仕様。
CakePHP 1.2.5で確認。

まずはCakePHPのマニュアルを確認。

メソッド :: Javascript :: 主要なヘルパー :: マニュアル :: 1.2 Collection :: The Cookbook

もともとあまり語られてません。APIリファレンスを覗いてみます。

CakePHP: the rapid development php framework: Api : JavascriptHelper

第3引数以降は廃止予定ですが(というかすでに使われてないように見える)、代わりに第2引数の$optionsにまとめる形になっています。
blockprefixpostfixstringKeysquoteKeysqとあるのですが、なんとJSON関数が有効なPHP環境で動作させた場合は、stringKeysquoteKeysqが無視されてしまいます。
下記のソースを参照すれば確認できます。

cake/libs/views/helpers/javascript.php::object()

if ($this->useNative) {
    $rt = json_encode($data);
} else {
    if (is_null($data)) {
        return 'null';
    }
    if (is_bool($data)) {
        return $data ? 'true' : 'false';
    }

    if (is_array($data)) {
        $keys = array_keys($data);
    }

    if (!empty($keys)) {
        $numeric = (array_values($keys) === array_keys(array_values($keys)));
    }

    foreach ($data as $key => $val) {
        if (is_array($val) || is_object($val)) {
            $val = $this->object($val, array_merge($options, array('block' => false)));
        } else {
            $quoteStrings = (
                !count($options['stringKeys']) ||
                ($options['quoteKeys'] && in_array($key, $options['stringKeys'], true)) ||
                (!$options['quoteKeys'] && !in_array($key, $options['stringKeys'], true))
            );
            $val = $this->value($val, $quoteStrings);
        }
        if (!$numeric) {
            $val = $options['q'] . $this->value($key, false) . $options['q'] . ':' . $val;
        }
        $out[] = $val;
    }

    if (!$numeric) {
        $rt = '{' . join(',', $out) . '}';
    } else {
        $rt = '[' . join(',', $out) . ']';
    }
}

613行目の$this->useNativeプロパティを見て分岐しています。614行目がJSON関数を使用する場合でelse以降がCakePHP独自の処理のようです。
見てわかるようにJSON関数には$dataしか渡していません。つまりoptionsで指定した上記のオプション類は使用されていないということがわかります。

ここで$this->useNativeが何なのか探ってみます。まぁ名前からしてネイティブの機能を使うか否かということでしょうが。

cake/libs/views/helpers/javascript.php

function __construct($options = array()) {
    if (!empty($options)) {
        foreach ($options as $key => $val) {
            if (is_numeric($key)) {
                $key = $val;
                $val = true;
            }
            switch ($key) {
                case 'cache':

                break;
                case 'safe':
                    $this->safe = $val;
                break;
            }
        }
    }
    $this->useNative = function_exists('json_encode');
    return parent::__construct($options);
}

コンストラクタで設定されていますが、json_encode関数の有無以外に何も制御されていません。
検索してもここしか出てこないのでこのままでは動的には変更不能です。

ということでJSON関数が有効な環境でstringKeys等を使いたい場合はCakePHPライブラリを書き換えるか、JavascriptHelperを継承したヘルパーを作るしかなさそうです。。。
(12/3追記)うそです。何言ってるんだ俺はw要はobjectメソッドを使う前にuseNativefalseにしてしまえばいいわけです。つまり下記のようなコードを噛ませばOKです。解決!

$javascript->useNative = false;
  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。




コメントを残す