Laravel DB操作いろいろ

# はじめに
何パターンかあったので使ったものをまとめてみた。

参考
https://readouble.com/laravel/5.7/ja/eloquent.html
https://www.ritolab.com/entry/120
https://blog.capilano-fw.com/?p=665
https://blog.capilano-fw.com/?p=699
http://kannokanno.hatenablog.com/entry/2017/06/02/202129
https://qiita.com/henriquebremenkanp/items/cd13944b0281297217a9

Laravel5.7

# 取得

### all get

```php:
$recodes = DBTest::all();
```

```php:
$recodes = DBTest::get();
```

どっちも同じ、Collection型で返ってくる。
配列のような中身なのでforeach等で取り出す。

### first

```php:
$recode = DBTest::first();
```

先頭の1レコードだけ取得、Model型で返ってくる。
`orderBy()`で並べ替えたり`where()`で制限すると目的のレコードが取れるかも。


### find

"id"カラムがあるならば`find()`が使える。

```php:
$recode = DBTest::find(1);
```

idを指定してレコードをModel型で受け取る。

```php:
$recodes = DBTest::find([1, 2, 3]);
```

idを複数指定したらCollection型で返ってくる。

### select

```php:
$recodes = DBTest::select('id')->get();
```

カラムを絞って取得。

### where

```php:
$recode = DBTest::where('id', '1')->first();
```

```php:
$recodes = DBTest::where('id','<=', '3')->get();
```

条件を指定して取得。


その他、SQL文で出来ることはEloquentでもできそう。


# 追加

### create



```php:
$val = DBTest::create([
    'num' => $request->num,
    'text' => $request->text
]);
```

`create()`は戻り値で、追加したレコードをModel形式で受け取れる。
追加したレコードにそのまま何か操作したいときに便利。
オートインクリメントで自動で入力されたidを取得、とかで使用した。

データ挿入を制限するfillableやguardedが必要。
入力を制限されたオートインクリメントでプライマリなカラムを入力しようとしてもエラーは出ず、入力した値ではなくインクリメントされた値が入る。

入力制限された通常のカラムに入力しようとするとエラーが出る。


### fill


```php:
$db_test = new DBTest();
$db_test->fill([
    'num' => $request->num,
    'text' => $request->text
]);
$db_test->save();
```

データ挿入を制限するfillableやguardedが必要。createと同じ。
createと違って一気にやらない。
`save()`するまでインサートされない。

### fillを使わないsave


```php:
$db_test = new DBTest();
$db_test->num = $request->num;
$db_test->text = $request->text;
$db_test->save();
```

データ挿入を制限するfillableやguardedに制限されない。

### insert

```php:
DBTest::insert([
    'num' => $request->num,
    'text' => $request->text,
    'created_at' => now(),
    'updated_at' => now()
]);
```

タイムスタンプを自動で更新しない。
データ挿入を制限するfillableやguardedに制限されない。


# 更新

### save


```php:
$db_test = DBTest::find($request->id);
$db_test->num = $request->num;
$db_test->text = $request->text;
$db_test->save();
```
**タイムスタンプが更新される。**戻り値は更新したレコード数たぶん。
データ挿入を制限するfillableやguardedに制限されない。


```php:
$db_tests = DBTest::where('id', '<=', '3')->get();
foreach ($db_tests as $db_test) {
    $db_test->num = $request->num;
    $db_test->text = $request->text;
    $db_test->save();
}
```

複数更新。

### update

```php:
DBTest::where('id', $request->id)->update([
    'num' => $request->num,
    'text' => $request->text
]);
```

**タイムスタンプが更新される。**この場合の戻り値は更新したレコード数。
fillableやguardedで制限されたカラムを更新しようとするとエラーは出ないがそのカラムは更新もされない。

```php:
DBTest::find($request->id)->update([
    'num' => $request->num,
    'text' => $request->text
]);
```

~~first()やfind()でModelとして取得した後にupdate()すると戻り値は成否(true, false)になる。~~
ならなかった、1が戻ってきた。

```php:
DBTest::where('id', '<=', '3')->update([
    'num' => $request->num,
    'text' => $request->text
]);
```

3レコード更新されて、ちゃんと3が戻ってきた。



# 削除

### destroy

```php:
DBTest::destroy($request->id);
```

"id"カラムがあるならば使える。idを指定して削除。
戻り値は削除したレコード数。


```php:
DBTest::destroy([1, 2, 3]);
```

複数指定もできる。戻り値は削除したレコード数だった(確認)。


### delete

```php:
DBTest::where('id', $request->id)->delete();
```

`where()`で指定して削除。戻り値は削除したレコード数。

```php:
DBTest::where('id', '<=', '3')->delete();
```

複数削除。

```php:
DBTest::query()->delete();
```
全て削除。`DBTest::delete()`で全て消えるかなって思ったらエラーが出た。`query()`が必要らしい。

### truncate

```php:
DBTest::truncate();
```

全て削除するなら`delete()`よりこっちがいいらしい。理由はオートインクリメントの値をリセットしてくれるから。
エラーをはいたから保留。





# モデル
プライマリキーが"id"以外のとき。

```php:モデル
class DBTest extends Model
{
    protected $primaryKey = 'test_id';
}
```

これを指定すると`find()`や`destroy()`の対象カラムになる。


---

追加や更新でタイムスタンプを自動更新したくないとき。

```php:モデル
class DBTest extends Model
{
    public $timestamps = false;
}
```

---

テーブル名がクラス名の大文字ごとに「_」で区切った複数形(クラス名が「DBTest」ならテーブル名は「d_b_tests」、クラス名が「DbTest」ならテーブル名は「db_tests」)ではない場合は`App\Memo::where()~`等のEloquent ORMが動作しなくなる。

そのような場合は以下のようにテーブル名を指定すると動作するようになる。

```php:モデル
class DBTest extends Model
{
    protected $table = 'db_test';
}
```

---

create()やfill()を使ってレコードを挿入するとき、カラムを指定してデータ挿入を禁止することができる。

```php:モデル
class DBTest extends Model
{
    protected $guarded = ['id'];
}
```

逆に`$fillable`を使えばデータ挿入が可能なカラムを指定できる。
`$guarded`と`$fillable`を同時に使うことはできない。



# 更新もしくは追加
https://awesome-linus.com/2019/07/03/laravel-upsert/

```php:
DBTest::updateOrCreate(
    ['id' => $request->id],
    ['num' => $request->num,'text' => $request->text]
);
```

指定したidが存在しなければ追加、存在すれば更新してくれる。
知らずにif文でやっていたので嬉しい。
戻り値は更新、追加されたインスタンスをModel型で返してくれる。



#おわり
今まで戻り値とか制限とか気にしないで使っていたものをちょっと調べて試してみた。
調べた結果と試した結果が結構違っていて戸惑い。試し方が悪いかもしれないので鵜呑みにはしないように。