CakePHP

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

CakePHP

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

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

301 Moved Permanently

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

301 Moved Permanently

第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;
スポンサーリンク
記事を書いた人

システムえんじにゃー🐈
趣味はエレキギター、自転車など。作曲したい。
World of Warshipsやってます。
記事に関する質問はお気軽にどうぞ。

surface0 (さーふぇす)をフォローする

コメント

タイトルとURLをコピーしました