Inflectorのトラップですなー

この記事はだいぶ前に書かれたものなので情報が古いかもしれません

CakePHPのCakeフォルダの中を見てみると、libsフォルダの下にこんなファイルがあるのが分かると思います。

Inflector.php

このライブラリは文字列の変換に一役買っているそうです。単数形を複数系に変換したり、アンダーバーをキャメルケースしたり、そういうことを行っているのがこのファイル……でいいのかしらん?


CakePHPのFormヘルパーでラジオボタンを出力するメソッドがあるじゃないですか。あれって、配列で値を渡すとその配列のキーを使って、各ラジオボタンのidが一意になるように上手いこと処理してるんですが、今日、それが上手く動かなくてですね……一言で言うと、ラジオボタンのidが全部同一のものになってたんですよ。当然それに紐づくラベルも同じ。だからどのラベルをクリックしても一番上のボタンにチェックがついてしまうという現象が起きました。

ヘルパーのform.phpの中を見てみると、ラジオボタンのidを振るところにInflectorっていう単語が出て来るんですよ。そこまでは僕にも分かったんですが、いかんせん僕は、コアライブラリのソースとか見ても何が何をやっているのかが理解できない。


で、知り合いに聞いてみたところ、どうもPHPのバージョンによって、Inflector.phpが正常に機能しないことがあるそうなんです。

ちなみに僕が動かなかったという環境のPHPのバージョンは、5.1.6でした。


CakePHP1.3.6(だと思う)のInflector.phpの一番下にあるslugというメソッドを見ると、こんなようなことが書いてあります。

function slug($string, $replacement = '_', $map = array()) {
  $_this =& Inflector::getInstance();

  if (is_array($replacement)) {
    $map = $replacement;
    $replacement = '_';
  }
  $quotedReplacement = preg_quote($replacement, '/');

  $merge = array(
    '/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
    '/\\s+/' => $replacement,
    sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
  );

  $map = $map + $_this->_transliteration + $merge;
  return preg_replace(array_keys($map), array_values($map), $string);
}

何をやっているのかはよく分かりませんが、何か特殊な文字に関する処理を行っているっぽい感じです。

これがいまいち上手く動いていないらしい。

そこでこのメソッドの中身をこんな風に書き替える。

function slug($string, $replacement = '_', $map = array()) {
  if (!class_exists('String')) {
    require LIBS . 'string.php';
  }
  $map = array(
    '/à|á|å|â/' => 'a',
    '/è|é|ê|ẽ|ë/' => 'e',
    '/ì|í|î/' => 'i',
    '/ò|ó|ô|ø/' => 'o',
    '/ù|ú|ů|û/' => 'u',
    '/ç/' => 'c',
    '/ñ/' => 'n',
    '/ä|æ/' => 'ae',
    '/ö/' => 'oe',
    '/ü/' => 'ue',
    '/Ä/' => 'Ae',
    '/Ü/' => 'Ue',
    '/Ö/' => 'Oe',
    '/ß/' => 'ss',
    '/[^\w\s]/' => ' ',
    '/\\s+/' => $replacement,
    String::insert('/^[:replacement]+|[:replacement]+$/', array('replacement' => preg_quote($replacement, '/'))) => '',
  );
  $string = preg_replace(array_keys($map), array_values($map), $string);
  return $string;
}

こう書き替えることによって何がどう変わるのかは分かりません。まあ、明らかにソースが変わってるので、何かが変わったのは分かります。



とりあえず、こう直すことで無事に動いたのは確認できました。知り合いに感謝です。

まだコメントはいただけてないみたい……
もしかしたら何か関連しているかも?