Laravel よく使うクエリビルダと複雑なwhere

#  DBファサードのテーブルメソッドを使ってクエリ文を作成してデータを取得する

DBファサードは select、update、insert、delete、statementのクエリタイプごとにメソッドが用意されている

>https://readouble.com/laravel/5.5/ja/queries.html
>データベースクエリビルダはスラスラと書ける(fluent)便利なインターフェイスで、クエリを作成し実行するために使用します。アプリケーションで行われるほとんどのデーターベース操作が可能で、サポートしている全データベースシステムに対し使用できます。

>LaravelクエリビルダはアプリケーションをSQLインジェクション攻撃から守るために、PDOパラメーターによるバインディングを使用します。バインドする文字列をクリーンにしてから渡す必要はありません。


# よく使うクエリビルダ

## select() 基本的なクエリの実行

```php:
$item = DB::select('SELECT * FROM items');
```

## DBからのデータ取得
### 基本 get()でテーブルのすべてのデータを取得

```php:
$items = DB::table('テーブル名')->get();

// Eloquent(Model)を作成するとDB::table()を使わなくて良くなる
// Itemモデルを作った場合
$items = App\Item::get();

// AppネームスペースでItemをuseで追加しておくとシンプルに書ける
use App\Item;
$items = item::get();
```

### first() 最初のひとつだけ取得

```php:
// たくさん得られるデータから最初のひとつだけ取得
// (並べ替えしていない場合idの昇順$id=1)
$items = Item::first();
```

### take() 個数を指定して取得

```php:
// 複数取得できる中から個数を選択して取得
$items = Item::take(3)->get();
```

### find() idを指定して取得

```php:
$item = Item::find(2);
```

### chunk() 指定の件数ごとに取得

```php:
// 2件ごとにデータを纏めて取得6件あった場合[2, 2, 2]のようなまとまりになる
$items = Item::chunk(2);
```
### select() カラム指定で取得

```php:
// nameのみ取得する場合
$items = Item::select('name')->get();
// 複数指定する場合(idとnameを取得する場合)
$items = Item::select('id', 'name')->get();
```
### value() 指定したかカラムの値を１つ取得
```php:
// where()で指定したレコードを取得する
// id=2,3の2つのレコードの場合where('id', [2, 3])
// valueでカラムを絞り込んで値を取得する
$items = Item::where('id', [2, 3])->value('name');
// この例ではid=2,3のnameカラムの値を1つ取得する
// このように配列でレコードを2つ指定しても値は1つしか取れない
```
### pluck() 指定したカラムの値すべて取得

```php:
// 指定したカラム名のデータをすべて取得
$items = Item::pluck('name');
// 第二引数にkeyを指定してkey=>valueの形で2つ取得できる
$items = Item::pluck('name', 'id');
    // $id => $name
```

### where(), orWhere 該当するデータだけ取得

```php:
// 'name'カラムが'名前1'のレコードを取得したい場合
$items = Item::where('name', '名前1')->first();

// A and B
// 'name'カラムが'名前1'でかつ'name'カラムが'名前2'のレコードを取得したい場合
$items = Item::where('name', '名前1')->where('name', '名前2')->first();

// A or B
// 'name'カラムが'名前1'のレコードもしくは'name'カラムが'名前2'のレコードを取得したい場合
$items = Item::where('name', '名前1')
        ->orWhere('name', '名前2')
        ->first();

// (A and B) or C (andが強いため特別な処理は必要ない)
// 'name'カラムが'名前1'かつ'name'カラムが'名前2'のレコードもしくは'name'カラムが'名前3'のレコードを取得したい場合
$items = Item::where('name', '名前1')
        ->where('name', '名前2')
        ->orWhere('name', '名前3')
        ->first();

// A or (B and C)
// 'name'カラムが'名前1'かつ'name'カラムが'名前2'のレコードもしくは'name'カラムが'名前3'のレコードを取得したい場合
$items = Item::where('name', '名前1')
        ->orWhere('name', '名前2')
        ->where('name', '名前3')
        ->first();

// A and (B or C)
// 'name'カラムが'名前1'のレコード、かつ'name'カラムが'名前2'もしくは'name'カラムが'名前3'のレコードを取得したい場合
$items = Item::where('name', '名前1')
        ->where(function($query) {
        $query->where('name', '名前2')
              ->orwhere('name', '名前3')
        })
        ->first();

// (A and B) or (C and D)
$items = Item::where('name', '名前1')
        ->where('name', '名前2')
        ->orWhere(function($query) {
        $query->where('name', '名前2')
              ->where('name', '名前3')
        })
        ->first();

// (A or B) and (C or D)
$items = Item::where(function($query) {
        $query->orWhere('name', '名前1')
              ->orWhere('name', '名前2')
        ->where(function($query) {
        $query->orWhere('name', '名前2')
              ->orWhere('name', '名前3')
        })
        ->first();

// 関数を使う場合で変数を使いたい場合はuseを使う
$items = Item::where('name', '名前1')
        ->where(function($query)use($user) {
        $query->where('name', '$user->name')
              ->orwhere('name', '$user->name')
          })
        ->first();
```

## ログインユーザー情報の取得

```php:
$user = Auth::user();
// ログインにかかわらず登録ユーザー情報を取得する場合は
$user = User::get();
```

### (補足)tinkerで認証をする場合

```php:
// そのままだと次のようになる
>>> Auth::user()
 => null
// 認証が済んでないのでidを指定してログインする
>>> auth()->loginUsingId(1);
// id確認も可能
>>> auth()->id()
 => 1
>>> Auth::user()
 => //
```

## リレーション先のデータを取得
### with() リレーション先と一緒に取得

```php:
// ItemがbelongsTo('App\Content');とする
$items = Item::with('contents')->get();


App\Order::join('users', 'orders.user_id', '=', 'users.id')->get()

```


## 取得したデータの保存
### save() 既存データと異なれば保存
データが同じであれば保存されずupdated_atも更新されない

```php:
$item = Item::find(1)
$item->name = $request->name;
$item->save();
```

### save前に更新されたか確認
isDirty()を使うことで変更されているかどうか確認ができる
変更されていればtrue、されていなければ（更新せずに更新ボタンが押された場合)falseを返す

```php:
$order = App\Order::find(1);
$order->price = 50000; // 変更前20000の場合
$order->isDirty() // 返り値true
$order->save();
```

### update() 既存データを確認せず更新保存
データが同じであっても上書きされupdated_atも更新される

```php:
$item = Item::find(1)->update(['name' => $request->name]);
```