アクセサ、ミューテタでlaravelのモデルを賢くする。

今までlaravelのモデルをDBバインドにしか使ってませんでした。
アクセサ、ミューテタで結構賢くすることができたのでメモします。

## アクセサ
モデルの値を取得する時にひと手間加えてくれる。

例）created_atを表示
```php:
    $model->created_at; // 2024-04-17T10:02:20.000000Z
    
    $model->created_at->format('Y/m/d H:i:s'); // 2024/04/17 19:02:20
```

モデルにアクセサを設定すると↓
```php:Models\user.php
use Illuminate\Database\Eloquent\Casts\Attribute; // 忘れずに

    //アクセサ
    public function createdAt() {
        return Attribute::make(
            get: function () {
                return $this->created_at->format('Y/m/d H:i:s');
            }
        );
    }
```
こうなります↓

```php:呼び出し側
    $model->created_at; // 2024/04/17 19:02:20
```
モデルではキャメル`createdAt()`なのに、
呼び出す時はスネーク`created_at`でもオッケーです🙆‍♀️



■ 関数名は変えてもオッケーです。
```php:Models\user.php
    //アクセサ
    public function createdDateTime() {
        return Attribute::make(
            get: function () {
                return $this->created_at->format('Y/m/d H:i:s');
            }
        );
    }
```
```php:呼び出し側
    $model->created_datetime; // 2024/04/17 19:02:20
```

■ 他のカラムを参照する場合。
例）is_member, is_admin, is_gestフラグを配列にする。
```php:Models\user.php
    protected function authorities()
    {
        return Attribute::make(
            //アクセサ
            get: fn ($value, $attributes) => array_filter([
                $attributes['is_member'] ? 'member' : '',
                $attributes['is_admin'] ? 'admin' : '',
                $attributes['is_gest'] ? 'gest' : '',
            ]),
        );
    }
```
```php:呼び出し側
    $model->authorities; // ['member', 'admin', 'gest']
```

## ミューテタ
モデルの値を格納する時にひと手間加えてくれる。
アクセサと逆の操作。
```php:Models\user.php
    protected function authorities()
    {
        return Attribute::make(
            // ミューテタ
            set: fn ($value) => [
                'is_member' => in_array('member', $value),
                'is_admin' => in_array('admin', $value),
                'is_gest' => in_array('gest', $value),
            ],
        );
    }
```
モデルに値を入れるとミューテタを通る。
```php:呼び出し側
    $model->authorities = ['member', 'admin'];
    // $model->is_member  1
    // $model->is_admin  1
    // $model->is_gest  0
```

■ アクセサ、ミューテタを両方設定する時はこう
```php:Models\user.php
    protected function authorities():
    {
        return Attribute::make(
            //アクセサ
            get: fn ($value, $attributes) => array_filter([
                $attributes['is_member'] ? 'member' : '',
                $attributes['is_admin'] ? 'admin' : '',
                $attributes['is_gest'] ? 'gest' : '',
            ]),
            // ミューテタ
            set: fn ($value) => [
                'is_member' => in_array('member', $value),
                'is_admin' => in_array('admin', $value),
                'is_gest' => in_array('gest', $value),
            ],
        );
    }
```
```php:Models\user.php
    protected function isMember()
    {
        return Attribute::make(
            get: fn ($value) => $value ? 'member' : '',
            set: fn ($value) => $value ? 1 : 0,
        );
    }
```

## キャスト　cast
アクセサ、ミューテタを設定するほどではないが型は守って欲しい時。
```php:Models\user.php
   protected $casts = [
        'is_member' => 'boolean',
        'is_admin' => 'boolean',
        'is_gest' => 'boolean',
    ];
```
```php:呼び出し側
    $model->is_member = '猫'; // 1
    $model->is_admin = 1111; // 1
    $model->is_gest = null; // 0
```
入れても出してもその型にキャストしてくれる。

## トレイト　trait
アクセサ、ミューテタ、その他の機能を切り出して共通化する。
こうやって新しいクラスを作っておくと。
```php:App\Traits\DateTrait.php
<?php

namespace App\Traits;

use Illuminate\Database\Eloquent\Casts\Attribute;

trait DateTrait {
    public function createdAtAsDate(){
        return Attribute::make(
            get: function () {
                return $this->created_at->format('Y/m/d');
            }
        );
    }
}
```
これだけで使える。
（SoftDeletes、HasFactoryなどと同じ）

```php:Models\user.php
// use Illuminate\Database\Eloquent\Factories\HasFactory;
// use Illuminate\Database\Eloquent\SoftDeletes;
use App\Traits\DateTrait;

class User extends Model
{
    // use HasFactory;
    // use SoftDeletes;
    use DateTrait;
    ...
```
```php:呼び出し側
    $model->createdAtAsDate; // 2024/04/17
```

***

いかがだったでしょうか。

**・アクセサ**
**・ミューテタ**
**・キャスト**
**・トレイト**
を使ってモデルを賢くさせましょう！