実装といっても基本的には、すでに五十音(のうちの一文字)を取得するところまではできているので、あとは where yomi like 'あ%' みたいなWHERE句を生成してデータ取得すればいいだけの話です。
なんですが、これがやってみると意外とメンドイ。まず一番ネックな部分は、普通に?フォームのテキストフィールドから入力された地名を検索する場合と、五十音パッドから一文字選択されてその文字で始まる地名を検索する場合、といった感じで一口に「検索」といっても多少挙動が違う感じになっているというところです。
具体的にはフォームからの検索の場合は where nc like '%函館市%' のようなクエリを組み立てていますが、五十音パッドの場合は where yomi(の一文字目) = 'あ' みたいなWHERE句を生成したい(しなければならない)ことです。
しかもフォームからの検索の場合は(ブラウザからの)クエリが複数ある可能性があるので配列で受け取っていますが、五十音パッドからの場合は今のところ単一の文字(五十音一文字)なのでわざわざ配列にする必要はありません。
そんなわけでやり方はいろいろ考えられますが、とりあえず一番手っ取り早く、検索モードというフラグ?を導入して、switch文で分岐させることにしました。
単純なif文でなくswtch文にしたのは、この後さらに検索モードが増える可能性を考慮してのことです。というか実は大元のスクリプトでは「普通のフォームからの検索」「五十音パッドからの検索」に加えて「IDでの検索?(検索というかID指定でデータを取ってくる感じ)」の3通りの検索モードがあり、実際switch文で分岐していてすでにぐっちゃぐっちゃで手のつけられない状況になっています(^^;。
というわけでまずControllerのsearch()とkanaSearch()に検索モードフラグをセットするコードを加えます。
Controller->search()
$this->phpsession->save('search_mode', 0);
Controller->kanaSearch()
$this->phpsession->save('search_mode', 1);
要するに通常検索は0/五十音パッドは1ってことにする、ということです。
そしてsearch()の方と同様に検索条件をセッションに格納して、ソート条件をクリアします。
kanaSearch()
//検索条件セット
$this->phpsession->save("search_key", $cap);
//ソート条件初期化(ORDER nid asc)
$this->phpsession->save("sort_key", serialize(array('field'=>'nid', 'order'=>'asc')));
search()の方はpostで送られてきたデータを格納していましたが、kanaSearch()ではURIの第3セグメントでURLエンコードされた平仮名一文字を受け取っていますので、それ($cap)をそのままセッションデータに格納します。そしてindex()にリダイレクト…。
index()
//検索条件取得
switch ($this->phpsession->get('search_mode'))
{
case 0:
$data['criteria'] = array('pref'=>'', 'nc'=>'', 'oc'=>'');
if ($this->phpsession->get('search_key') <> '')
{
$condition = unserialize($this->phpsession->get('search_key'));
foreach ($condition as $key => $value)
{
$data['criteria'][$key] = $value;
}
}
break;
case 1:
$data['criteria'] = '';
if ($this->phpsession->get('search_key') <> '')
{
$data['criteria'] = $this->phpsession->get('search_key');
}
break;
}
index()の検索条件取得部分では、まず検索モードを調べてswitch文で分岐します。$data['criteria']は通常検索の場合は配列ですが、五十音検索の場合は配列にはなりません。
そしてModelもControllerと同じようにswitch文で分岐させて、それぞれの検索モードに合ったWHERE句を生成するようにします。
switch ($this->phpsession->get('search_mode'))
{
case 0:
$this->db->like(array_diff($criteria, array('', NULL)));
break;
case 1:
$field = "yomi";
if (get_cookie('kanatab') <> '')
{
if (get_cookie('kanatab') == 'ocap')
{
$field = "oyomi";
}
}
$where = "SUBSTRING($field FROM 1 FOR 1) = ".$this->db->escape($criteria);
$this->db->where($where);
break;
}
ここで$fieldというのは新旧どちらの地名の読みフィールドかを表す変数です。これは五十音パッドの上部のタブの選択状態で振り分けています。
WHERE句はほとんど手動生成(笑)なので、$this->db->escape()でエスケープ処理しています。SUBSTRINGは前回と同じMySQL側の文字列操作関数です。
動作結果(発行されたクエリだけキャプチャ)
で、一応ほぼ期待通りに動作しました。↑の画はデバッグ出力の部分だけですが、ちゃんと期待通りのクエリが発行されてる様子はわかるとおもいます。
しかしながら、どーも気に食わないというか…。switch文を導入?すると途端にスクリプトが長くなりますね。ってゆーか汚い(--;まだ検索モードが2つだけなのでそれほどでもないですが、これが3つとかになるとせっかくCodeIgniter使って書き換えてる意味が半減しちゃうような気が…。
それとこれは今回の実装とは直接関係ありませんが、旧市町村の頭文字で検索された時にはその頭文字だけを持つ旧市町村名だけを出力するようにしたほうがいいような気がしてきました。
今の状態だと旧市町村の「お」をクリックすると…
北海道|せたな町|大成町|2005-09-01
|瀬棚町|
|北檜山町|
北海道| 釧路市 |釧路市|2005-10-11
|阿寒町|
|音別町|
こんな感じで「おおなりちょう」や「おとべつちょう」はちゃんと出力されますが、それと一緒に合併した旧市町村=瀬棚町、北檜山町なども同時に出力されてしまいます。これを…
北海道|せたな町|大成町|2005-09-01
北海道| 釧路市 |音別町|2005-10-11
このような出力にした方がよいのではないか?ということです。
で、これは比較的簡単に旧市町村のタブがクリックされている時は、クエリで外側のSELECTにもWHERE条件句をつけてやればいいだけです。まあそのための場合分けとかは多少必要ですが、一応そのような実装に変更しました。
ですがやはりswitch文だけはどうしても気に入らず、結局却下することにしました。なので今回の実装は、まあ無駄といえば無駄な作業だったってことで(--;。。。
ラベル:codeigniter