2015.6.30
0からはじめるPHP#30【Laravel5で作るデータベース#4-データベース検索-】
ということで、コントローラーの話に戻ります。
タイトルにデータベース検索ってつけてるぐらいなので、検索の話をします。つまり、データベースで最も重要な部分の話をするわけですね。
public function index()
{
$tests = DB::table('tests')->get();
return view('viewname')->with('tests',$tests);
}
おさらいですが、
#28でデータベースの取得はこのようにするといいました。
testsというデータベースを取得し、get()でそれをオブジェクト化して$testsに代入しているんですね。これが基本です。
では、ここからどのように検索していくのでしょうか。
せっかくなので
私が今制作しているデータベースをサンプルに解説していきます!
じゃん。
ちなみに開発コードネームは
Musel(ミュゼル)です。Music Selectorです。
受け入れてもらえるかどうかは不明ですが僕は気に入っています。
別にミュゼのパクリじゃないです。参考にしただけです。
ちっさくて見にくいかも知れませんが、まぁ分かるでしょう。上にフォームがありますね。ここで具体的な検索条件を入力してもらいます。
一通り完成したらバリデーションとかやるつもりですけど、今はあまり考えないことにしてるんですが、それでも下手なことができないように基本的にはテキストフォームでなくセレクトボックスを使ってます。
半角と全角の区別すらつかない人っていますしね。実際に後輩に居てびっくりしました。
別にこれは普通にget送信したら良いだけです。フォームに関してはフレームワークに関係ないので省きます。
//DB配列(ただしint型カラムのみ。DBと同じ名前にしてください。ドットは使えません。項目表示したいカラムをここに書けば反映されます。)//
$parameter_DB=array("Fl","(Picc)","Ob",'(E_hr)',"Cl","(Es_Cl)","(Bass_Cl)","Fg","(C_Fg)","Hr","Tp","(Crnt)","Trb","Tub","Perc","(Timp)","Hp","Pf","Cel");
foreach($parameter_DB as $parameter){
$parameter_m[]=$parameter."m";
$parameter_M[]=$parameter."M";
}
$results=DB::table('compositions');//DB読み込み
$inputs = \Request::all();//送られた配列データを保存
if(!isset($inputs["STimem"])){
//全表示//
$results=$results->leftJoin('composers','composers.composer_id','=','compositions.composer_id')
->leftJoin('genres','genres.genre_id','=','compositions.genre_id')
->leftJoin('tonalities','tonalities.tonality_id','=','compositions.tonality_id')
->leftJoin('countries','countries.country_id','=','composers.country_id');
}else{
//検索条件あり//
$results=$results->whereBetween('time', [$inputs["STimem"],$inputs["STimeM"]]);//時間指定
//楽器
$i=0;
foreach($parameter_DB as $column){
$results=$results->whereBetween($column, [$inputs[$parameter_m[$i]],$inputs[$parameter_M[$i]]]);
$i++;
}
//分類
if(ctype_digit($inputs["Genre"])){
$results=$results->where('compositions.genre_id', '=', $inputs["Genre"]);
}
~略~
$results=$results->leftJoin('composers','composers.composer_id','=','compositions.composer_id')
->leftjoin('genres','genres.genre_id','=','compositions.genre_id')
->leftJoin('tonalities','tonalities.tonality_id','=','compositions.tonality_id')
->leftJoin('countries','countries.country_id','=','composers.country_id');
}
/*ソート*/
if(isset($inputs["sort"])){
if($inputs["sort"]=="composer"){
$results=$results->orderBy('composer' ,$inputs["option"]);
}else{
$results=$results->orderBy('compositions.'.$inputs["sort"] ,$inputs["option"]);
}
}
$results=$results->get();//テーブル生成
具体的には、途中略してますがこのように実装しています。
上から順に見ていきますと、まずデータ取得は9行目の
\Request::all()で受け取ってます。これは受け取ったデータすべてを配列に代入する命令です。
もちろん、getとpostをそれぞれ受け取る命令も確かあったと思います。Inputファサードだったかな?ちなみに、Requestの前のバックスラッシュは必要です。名前空間とかの絡みらしいんですが、具体的なことは僕はわかりません。(笑)
具体的にどんな風に入ってるのかは、var_dumpで吐き出してみてくれれば分かるかと思います。
で、具体的に検索はどのようにするか、ということですが、どうやっても処理は分けなくてはいけないですよね。
ただ、ここで一つ注意してしまうと
get()を行ってオブジェクト化してしまうともう操作できないということです。
具体的にどうするのか、というと、例えば17行目を見て下さい。一旦セミコロンで処理を中断していますよね。これでいいんです。
最終的に、51行目でget()されます。このようにすることで処理を分割することができる、というのがまず一つの重要なことです。
$results=$results->whereBetween('time', [$inputs["STimem"],$inputs["STimeM"]]);//時間指定
//楽器
$i=0;
foreach($parameter_DB as $column){
$results=$results->whereBetween($column, [$inputs[$parameter_m[$i]],$inputs[$parameter_M[$i]]]);
$i++;
}
具体的な検索部分に関しては、このように絞り込んでいます。
まず、時間の最小最大を[STimem],[STimeM]というパラメータで受け取っているのですが、これを
whereBetweenで指定します。
このように、$resultをget()しない限り、後付で処理をすることができるわけですね。
ちなみに、1行目の意味ですが
"time"カラムの値が["STimem"]から["STimeM"]の間にあるものを取ってこいっていう意味になります。
あ、別に内容には関係ない話なので省きましたが、カラムの名前を配列に設定することでこのようにforeachで回して処理できるのでおすすめです。まぁ当たり前の話ですけど。(笑)
//調性
if(ctype_digit($inputs["Tonality"])){
$results=$results->where('compositions.tonality_id', '=', $inputs["Tonality"]);
}
先ほどの例は範囲検索でしたが、一致検索には
whereを用います。
上の例でいうと
"compositions"テーブルの"tonality_id"が["Tonality"]とイコールであるものを持ってこいという意味になります。
言ってなかったかも知れませんが、基本的にはテーブル名もきちんと書いた方がいいかなと思います。Joinした後だと混同しますし、気づかないうちにAmbiguityエラーがでたりしますしね。
if(isset($inputs["sort"])){
if($inputs["sort"]=="composer"){
$results=$results->orderBy('composer' ,$inputs["option"]);
}else{
$results=$results->orderBy('compositions.'.$inputs["sort"] ,$inputs["option"]);
}
}
最後にソートです。
ソートはorderByというものでやります。
ちょっと上の例は
変数が多すぎてサンプルもクソもないので、分かりやすいものにします。
/*昇順の場合*/
$results=$results->orderBy('テーブル名.カラム名' ,'asc');
/*降順の場合*/
$results=$results->orderBy('テーブル名.カラム名' ,'desc');
これでソートされます。
ちなみに、先ほどのソート部抜粋の例と見比べてみると分かると思うのですが、テーブル名とかは変数で指定しても当然動きます。
なので、これを利用することでコードを減らせたりします。色々試してみてください。
ただ、この例ではsortするだけなので実害はないような気もしますが、あんまりこういうことするときちんとバリデーションを定めとかないとSQLインジェクションとかされかねませんしね。
例えば、この例だと変数を使ってSQL文を組み立てているのですが、SQLインジェクションに関してはLaravelの方でやってくれてると思うのでいいんですが、セカンドオーダーSQLインジェクションに関してはどうなんでしょうね。
ちょっとこの辺は調べてもすぐには出てこなかったので保留にしておきますが、仮に何もされていない場合、このように変数で指定した場合はセカンドオーダーSQLインジェクションの餌食になります。シングルクォーテーションを適切にエスケープしなければなりません。
webシステム開発をする際は、そういうことも頭に入れて開発しないといけないんですよ、ということはいかなる時でも忘れてはいけないことではあります。
ということで、あとはこれをgetしてwithでビューに渡したら検索結果を表示できます。
是非試してみてください。データベースが面白くなってきます。(笑)