2007年11月16日

CodeIgniter:複数の検索フィールドの作成

前回、表示をテーブルタグで整形できたところで、ようやくアプリケーションらしくなってきましたが、今回はいままで新市町村名でしか検索できなかったformを旧市町村や都道府県でも検索できるように改造?してみたいとおもいます。

まず旧市町村名で検索できるようにVIEWでテキストフィールドを作ります。

VIEW
新市町村:<?=form_input('newcity', $newcity)?><br />
旧市町村:<?=form_input('oldcity', $oldcity)?>

見てのとおり新市町村のフィールドをごっそりコピーしただけです。

次にCONTROLLERのsearch()でも同じように新市町村のpostデータをセッションに格納しているところをコピペします。
$this->phpsession->save('newcity', $this->input->post('newcity'));
$this->phpsession->save('oldcity', $this->input->post('oldcity'));

さらにindex()でセッションデータを受け取って検索条件に入れているところも同様にコピペします。
$data['criteria']['newcity'] = ($this->phpsession->get('newcity') <> "") ? $this->phpsession->get('newcity') : "";
$data['criteria']['oldcity'] = ($this->phpsession->get('oldcity') <> "") ? $this->phpsession->get('oldcity') : "";

ただしこの部分は以前は$data['newcity']として受取っていましたが、配列化して$data['criteria']['newcity|oldcity']みたいな感じにしておきます。そのため下の件数取得の部分も$data['criteria']を渡すように変更しておきます。
//件数取得
$count = $this->Gdb->getCount($data['criteria']);

次にMODELのgetCount()で検索条件を受け取ってクエリを組み立てている部分を下のように修正します。これもとりあえずコピペです。
$this->db->like('nc', $criteria['newcity']);
$this->db->like('oc', $criteria['oldcity']);

これでとりあえずブラウザをリロードしてみます。おっとVIEWでエラーがでちゃいました。$data['newcity']だったものを$data['criteria']['newcity']にしたのを忘れてました。ということで…

VIEW
新市町村:<?=form_input('newcity', $criteria['newcity'])?><br />
旧市町村:<?=form_input('oldcity', $criteria['oldcity'])?>

に変更します。

oldcity.pngこれでとりあえずリロードするとエラーもなくフィールドも2つ表示されています。試しに「旧市町村=椴法華」みたいに検索してみた様子です。ちなみに新市町村「市」旧市町村「町」などのようにするとAND検索になります。ページングも問題ありませんでした。で、完成!といきたいところですが問題がなくもないです。

例えば次に都道府県名で検索したいといった時に、まあVIEWにテキストフィールドを付け足すぐらいはやるとしても、また同じようにコードを修正していかなければなりません。

そこで何かうまい考えはないものかと、もう一度上でやったことを反芻してみると、ModelクラスのgetCount()に渡す検索条件を配列にしたことに思い当たります。受取った方はまたぞろ同じようなコードをコピペしているわけですが、このあたりを修正していくことでなんかできそうな感じです。

そこでgetCount()の中で実際にWHERE句を組み立てている$this->db->like();をユーザガイドで調べてみると2番目に連想配列を使用する方法として引数に連想配列を渡しています。そしてこの場合は配列のキーが検索対象フィールド名になるわけです。

ということでまず
$this->db->like('nc', $criteria['newcity']);
$this->db->like('oc', $criteria['oldcity']);

を単に
$this->db->like($criteria);

に変更します。

でこのままだとnewcity like '%検索条件%'のようなWHERE句になってしまうので、この配列のキーを設定しているControllerの部分を変更します。
$data['criteria']['nc'] = ($this->phpsession->get('newcity') <> "") ? $this->phpsession->get('newcity') : "";
$data['criteria']['oc'] = ($this->phpsession->get('oldcity') <> "") ? $this->phpsession->get('oldcity') : "";

Viewも同様に変更します。
新市町村:<?=form_input('newcity', $criteria['nc'])?><br />
旧市町村:<?=form_input('oldcity', $criteria['oc'])?>
これでModelのgetCount()の部分のコードは多少すっきりしましたが、まだControllerは冗長的な印象です。そこでよくよく見るとセッションデータに格納しているデータが配列ではないために、いちいち冗長な記述になっているような気がします。

そこでセッションデータ格納時に配列で格納して、取り出し時も配列をforeachなどで処理するように書き換えられれば、もうすこしすっきりしそうな感じです。

そこでまずControllerのsearch()でセッションデータに格納しているところですが、postデータを受け取っているのでこれは配列になっていません。なのでまずはpostデータを配列として受取れるようにViewを変更します。
新市町村:<?=form_input('condition[nc]', $criteria['nc'])?><br />
旧市町村:<?=form_input('condition[oc]', $criteria['oc'])?>

つまりformのテキストフィールドのnameを配列にしてしまうわけです。

※尚、通常PHPで連想配列を書く場合は$array['name']のようにシングルコーテーションで括るとおもいますが、↑のコードで"condition['nc']"のように書いてしまうと、Disallowed characterみたいなエラーが出てしまうので上記のようになっています。理由はわかりません(--;

次にセッションデータに格納している部分を
$this->phpsession->save('search_key', serialize($this->input->post('condition')));

のようにpostの配列を渡すようにします。ですがそのままだとまずいのでserialize化します。

さらにControllerでセッションデータを読み出している部分を以下のように変更します。
if ($this->phpsession->get('search_key') <> '')
{
$condition = unserialize($this->phpsession->get('search_key'));

foreach ($condition as $key => $value)
{
$data['criteria'][$key] = $value;
}
}

これでブラウザで確認すると以下のように新市町村および旧市町村での検索ができています。
array_session.png
で、大筋では?これでいいとおもうんですが、例えば検索結果が0件だった場合の処理とか、新市町村の検索条件はあるけど旧市町村が空だった場合にも oc like '%%' というクエリが組み立てられていたりとか、微妙に気になったところを修正します。

Controllerで$countだったものを$data['count']に変更してViewで読み出せるようにします。Viewでは$countを調べて0件より多ければテーブルを出力するようにします。
<?if($count>0):?>

これで0件だった時はforeachに$datasが渡されませんので、Invalid argument supplied for foreach()みたいなエラーは出なくなります。

次にModelのクエリ組立部分でdb->like()に検索条件配列を渡していたところを
$this->db->like(array_diff($criteria, array('', NULL)));

のように変更し値がない要素は出力しないようにします。

array_diff.pngこの画面では旧市町村=函館市という検索条件でサブミットしていますが、新市町村は空です。以前までだとクエリには nc like '%%' のような不要な部分も組み立てられていましたが、画の通りWHERE句は oc like '%函館市%' だけになっています。

これでだいぶスッキリしてきたとおもいます。次回は1ページ毎の表示件数をユーザが変更できるようにしてみたいとおもいます。
ラベル:codeigniter
posted by ciallost at 14:45| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック