2007年11月19日

CodeIgniter:ソート機能を付けてみる

前回はチェックボックスの実装?をしてみましたが、今回はテーブル出力された表にソート機能を加えてみたいとおもいます。

できあがりイメージとしては、表の項目部分(つまり<th>タグで出力されているところ)をクリックするとその項目での昇順/降順でソートされる…のようなよくあるパターンのやつです。

手順的には、まずクリックされた項目などからデータベースのどのフィールドをどの方向にソートするかという情報をセッションデータに格納し、index()ではセッションデータを読み出して、データベースクエリにORDER句を用いてソートされたデータを出力…といった感じにします。

そこでまずModelのControllerから呼ばれるgetCountとgetDataにソート項目とソート方向の要素ををもつ配列$sort_keyという引数を一つ増やします。
function getCount($criteria, $sortkey)
function getData($offset, $limit, $sortkey)

次にクエリ組立部分に$sortkeyを使ってORDER句を加えます。
$this->db->orderby($sortkey['field'], $sortkey['order']);

次にControllerにsort()メソッドを追加します。
function sort($field='nid')
{
//ソート方向セット
$order='asc';
$now_order = unserialize($this->phpsession->get('sort_key'));
if ($field == $now_order['field'] && $now_order['order'] == 'asc')
{
$order = 'desc';
}
//ソート条件セット
$this->phpsession->save("sort_key", serialize(array('field'=>$field, 'order'=>$order)));
redirect('gappei/index/');
}

基本的にはsort_keyというセッションデータを格納しているだけですが、ソート方向を決めている部分が若干汚い感じになってしまいました。ロジックとしては基本的には昇順でフィールド名が前回ソートされたフィールド名と同じで向きが昇順だった場合のみ降順に設定します。つまり同じ項目を続けて2回クリックした場合は降順になるということです。そしてindex()で読み出します。
//ソート条件取得
$data['sort_key'] = array('field' => 'nid', 'order' => 'asc');

if ($this->phpsession->get('sort_key') <> '')
{
$data['sort_key'] = unserialize($this->phpsession->get('sort_key'));
}

次にViewですがこれまでは<th>タグを直に打っていましたが、アンカーやソート方向のマークなどを出力しなければならないので、別途関数を作って出力する形に書き直してみました。
function setTableHeading($th, $sort)
{
$th_tag = '';

foreach ($th as $field => $column)
{
$th_tag .= "<th>";
$th_tag .= anchor('gappei/sort/'.$field, $column);
if ($field == $sort['field'])
{
$order_mark = $sort['order']=='asc' ? '▽' : '△';
$th_tag .= " <span id=\"order_mark\">".$order_mark."</span>";
}
$th_tag .= "</th>\n";
}

return $th_tag;
}

引数は実際のデータベースのフィールド名をキーにテーブル出力する際の項目名を値とした連想配列、及びソートフィールドとソート方向を持った連想配列の2つの配列になります。

基本的にはCodeIgniterのanchorメソッドを使ってsort()メソッドを呼び出すリンク付きの項目名を出力しているだけです。ソートに使用されている項目名の場合はソート方向を表すマークも出力します。

そして今まで<th>タグを書いていた所から、上の関数を呼び出して出力する…みたいな感じです。
setTableHeading(array('pref'=>'都道府県',
'nc'=>'新市町村',
'oc'=>'旧市町村',
'gdate'=>'合併日'),
$sort_key);

で、これで一応動作はしますが、旧市町村をソートキーにした場合はうまくありません。これは発行しているクエリの問題で、要するに内側のサブクエリ時点でLIMITをかけている為ORDER句も基本的にはサブクエリ内に書く必要がありますが、旧市町村はサブクエリ時点では拾ってきていないので、その場合だけ外側のクエリでもORDERをかける必要があるということです。なので…

Model(外側のクエリ組立部分)
//旧市町村でソートする場合
if ($sortkey['field'] == 'oc')
{
$this->db->orderby($sortkey['field'], $sortkey['order']);
}

という感じでソートキーが旧市町村の時だけORDER句を生成するようにします。

あとここまでのコードだと一度項目をクリックしてしまうとリセットをかける手段がないので、新たに検索ボタンが押された場合はソート条件をリセットするようにsearch()メソッドに…
//ソート条件初期化(ORDER nid asc)
$this->phpsession->save("sort_key", serialize(array('field'=>'nid', 'order'=>'asc')));

を追加します。これは実際にはリセットというよりnid(=新市町村のID)で昇順にソートしています。

表示結果
sort.png

なんとなく駆け足で実装してしまいましたが、果たしてこんなのでいいのか?という不安はどこまでいってもついて回ります(--;特にViewファイルにfunctionを作ってそれを呼び出しているところなんかは、本当にここに書いてもいいのか?感がひとしおです。でも一応こんな適当な実装でも動くってことで…。
タグ:codeigniter
posted by ciallost at 20:45| Comment(2) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
いつもブログを読ませて頂いています。
とても参考になります!

私も最近CIを本格的に触って、開発の容易さに
感動しています。

それまでは、恥ずかしながら全てのコードを
「手続き型」で書いて、さらにはロジックとビューが
渾然一体とした(今思うと)不気味なファイルを
作りまくっていました。

これからも執筆活動を継続してください!
Posted by toomoo at 2007年11月20日 21:19
【祝】初コメント(たぶん)
ありがとうございます。
素人の拙い文章&コードですが参考になれば幸です。
またコードのミス・誤字・脱字等ございましたら
どしどし指摘して頂けるとありがたいです。
今後ともよろしくお願いします。
Posted by ciallost at 2007年11月20日 23:00
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

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


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/67635979

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

この広告は1年以上新しい記事の投稿がないブログに表示されております。