[メモ]Eloquentの利用方法(1)



[Laravel　公式ドキュメント](https://readouble.com/laravel/5.4/ja/eloquent.html)に基づいて作成したものです。


##モデル定義
全てのEloquentモデルは、`Illuminate\Database\Eloquent\Model`を拡張する必要があります。
<details><summary>モデルの作成に使えるArtisanコマンド</summary>
<div>
モデルの作成:

```
php artisan make:model User
```

モデル作成時にデータベースマイグレーションも生成:

```
php artisan make:model TestModel -m
```

注；データーベースにテーブルを作成する：

```
＄　php artisan migrate
```
</div>
</details>
## Eloquentモデル規約


<details><summary>モデル名</summary>
<div>
Laravelで定められたモデルとテーブル名の対応関係例：
Flight(モデル)-----Flights(テーブル)

[カスタムテーブル名を指定する(本文を参照)](https://readouble.com/laravel/5.4/ja/eloquent.html)
</div>
</details>


<details><summary>主キー</summary>
<div>
Eloquentはテーブルの主キーがid、デフォルト状態で主キーがint、自動増分される整数
自動増分ではないを使う：モデルにpublicの`$incrementing`プロパティーを用意し、falseをセット
</div>
</details>


<details><summary>タイムスタンプ</summary>
<div>
created_at(作成時間)とupdated_at(更新時間)は自動更新
自動更新を利用しない：モデルの`$timestamps`プロパティーをfalseに設定
タイムスタンプのフォーマットをカスタマイズ：モデルの`$dateFormat`プロパティーを設定
タイムスタンプを保存するカラム名をカスタマイズする：モデルに`CREATED_AT`と`UPDATED_AT`定数を設定
</div>
</details>

<details><summary>データベース接続</summary>
<div>
アプリケーションに設定されているデフォルトのデータベース接続を使用
異なった接続を使用したい：モデルに`$connection`プロパティーを使用
</div>
</details>


##モデルの取得
<details><summary>全レコードを取得</summary>
<div>
(取得されるのは`$flights`モデルのCollectionインスタンスです)

```php
$flights = App\Flight::all();

```
</div>
</details>

<details><summary>制約の追加</summary>
<div>
Eloquentモデルはクエリビルダとしても動作しますのでクエリに制約を付け加える
結果を取得するにはgetメソッドを使用
[クエリビルダ](https://readouble.com/laravel/5.4/ja/queries.html)
</div>
</details>

<details><summary>コレクション</summary>
<div>
allやgetで取得した`Illuminate\Database\Eloquent\Collection`インスタンスのメソッドでEloquent結果を操作

[コレクションについて詳しいドキュメント](https://readouble.com/laravel/5.4/ja/eloquent-collections.html#available-methods)
</div>
</details>

<details><summary>結果の分割</summary>
<div>
数千のEloquentレコードを処理：`chunk`コマンド

```php
//一番目の引数:いくつのレコードを処理するか
//二番目:クロージャ閉包関数
Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});
```
</div>
</details>


<details><summary>データベース全体を繰り返し処理</summary>
<div>
`cursor`メソッドを使用

```php
foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
}

```
</div>
</details>


次に、コレクションの代わりに、これらのメソッドは１モデルインスタンスを取得して処理する方法を紹介：

#モデル／集計の取得
<details><summary>主キー（id）で指定したモデル取得</summary>
<div>

```php
$model=Model::find(id)

```
</div>
</details>

<details><summary>主キー（id）の配列で指定したモデル取得</summary>
<div>

```php
$model=Model::find([1,2,3]);
```
</div>
</details>


<details><summary>クエリー条件にマッチした最初のレコード取得</summary>
<div>

```php
$model=Model::where('colum',value)->first()
```
</div>
</details>

##例外

モデルが見つからない時に、例外を投げる

```php
$model=Model::findOrFail(id)
```


```php
$model=Model::firstOrFail()
```

##集計の取得

```php
$count=Model::where('column',2)->count();
$max=Model::where('coulmn',1)->max
```

#モデルの追加と更新
##追加
```php
$model=new Model;
$model->name=$request->name;
//saveメソッドが呼ばれると新しいレコードがデータベースに挿入されます。
//saveが呼び出された時にcreated_atとupdated_atタイムスタンプは自動的に設定されます
$model->save();

```

##更新

```php
$model=Model::find(1);
$model->name='xxxx';
$model->save();

```
複数モデル更新:複数モデル更新を行う時、実際にモデルが取得されるわけではない

```php
App\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);

```

##複数代入
脆弱性を防ぐために、最初に複数代入したいモデルの属性を指定する必要がある。
<details><summary>モデルの`$fillable`プロパティで指定。（ホワイトリスト）</summary>
<div>

```php
protected $fillable = ['name'];
```

</div>
<details>

<details><summary>新しいレコードをデータベースに挿入：`create`を利用</summary>
<div>

```php
$flight = App\Flight::create(['name' => 'Flight 10']);
```
</div>
<details>

<details><summary>既に存在するモデルインスタンスへ属性を指定：`fill`を使う</summary>
<div>

```php
$flight->fill(['name' => 'Flight 22']);
```
</div>
<details>

##属性の保護
<details><summary>複数代入したくない属性の配列を指定：`$guarded`プロパティーを使用(ブラックリスト)</summary>
<div>

```php
//priceだけは複数代入したくない
protected $guarded = ['price'];
```

</div>
<details>

<details><summary>全属性を複数代入可能：`$guarded`をクリアする</summary>
<div>

```php
protected $guarded = [];
```
</div>
<details>

##他の生成メソッド
`firstOrCreate`->
まず指定のレコードをデーターベースに見つけ、ない場合は新しいレコードを挿入
`firstOrNew`->
まず指定のレコードをデーターベースに見つけ、ない場合は新しいモデルインスタンスを生成するが、データーベースに保存されないので、saveを呼び出す必要があります。
`updateOrCreate`->
既存のモデルを更新するか、存在しない場合は新しいモデルを作成。

#モデル削除
<details><summary>モデルによる削除:`delete()`</summary>
<div>

```php
$flight = App\Flight::find(1);

$flight->delete();
```

</div>
</details>


<details><summary>キーによる既存モデルの削除:`destroy(id)`</summary>
<div>

```php
App\Flight::destroy(1);

App\Flight::destroy([1, 2, 3]);

App\Flight::destroy(1, 2, 3);
```
</div>
</details>

<details><summary>クエリーによるモデル削除</summary>
<div>

```php
$deletedRows = App\Flight::where('active', 0)->delete();
```

</div>
</details>


#ソフトデリート

<details><summary>1.ソフトデリートを有効にする</summary>
<div>

モデルに`Illuminate\Database\Eloquent\SoftDeletes`トレイトを使い、`deleted_at`カラムを`$dates`プロパティに追加します。

</div>
</details>


<details><summary>2.データベーステーブルに`deleted_at`カラムを追加する</summary>
<div>

スキーマビルダに作成するメソッド`softDeletes()`を使用。

</div>
</details>

<details><summary>3.モデルをソフトデリートする</summary>
<div>
モデルに対し`delete`メソッドを使用
</div>
</details>

<details><summary>4.削除の確認</summary>
<div>`trashed`メソッドを使用。</div>
</details>


#ソフトデリート済みモデルのクエリ
ソフトデリートされたモデルは自動的にクエリの結果から除外されます。
<details><summary>1.ソフトデリート済みのモデルを含めるように強制したい場合：クエリに`withTrashed()`メソッドを使う。</summary>
<div>

```php
$flights = App\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();
```

</div>
</details>

<details><summary>2.ソフトデリート済みモデルのみの取得:`onlyTrashed()`メソッドを使用</summary>
<div>

```php
$flights = App\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();
```
</div>
</details>

<details><summary>3.ソフトデリートの解除:`restore()`</summary>
<div>
ソフトデリート済みのモデルを「未削除」に戻したい場合->モデルインスタンスに対し`restore()`メソッドを使用

```php
$flight->restore();
```

</div>
</details>

#モデルの完全削除
forceDelete()を使う

```php
// １モデルを完全に削除する
$flight->forceDelete();

// 関係するモデルを全部完全に削除する
$flight->history()->forceDelete();
```