Laravel ORM（Eloquent）チートシート


# Laravel ORM（Eloquent）チートシート

## モデル操作の詳細

### モデルの定義
```php
class User extends Model
{
    // テーブル名の指定（デフォルトはモデル名の複数形）
    protected $table = 'users';

    // 更新可能なカラム
    protected $fillable = ['name', 'email', 'password'];

    // 非表示にするカラム（例: JSONシリアライズ時）
    protected $hidden = ['password'];

    // キャストするデータ型
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}
```

### データの取得（詳細）
```php
// 全件取得
$users = User::all();

// 条件付き取得（1件だけ）
$user = User::where('email', 'example@example.com')->first();

// 複数のIDで取得（whereIn）
$users = User::whereIn('id', [1, 2, 3])->get();

// 特定のカラムのみ取得（pluck）
$emails = User::pluck('email');

// 一意の値のみ取得（distinct）
$distinctEmails = User::distinct()->pluck('email');
```

## クエリビルダーの詳細

### 条件付きクエリ

- `where` やその派生系を使って、条件を指定できます。

```php
// 単一条件
$users = User::where('active', 1)->get();

// AND条件
$users = User::where('active', 1)->where('role', 'admin')->get();

// OR条件
$users = User::where('active', 1)->orWhere('role', 'admin')->get();
```

### whereの応用

- `whereIn`: 指定した値のリストの中にあるかをチェック
```php
$users = User::whereIn('id', [1, 2, 3])->get();
```

- `whereNotIn`: 指定したリストに含まれていないもの
```php
$users = User::whereNotIn('id', [1, 2, 3])->get();
```

- `whereBetween`: 値が指定範囲にあるかをチェック
```php
$users = User::whereBetween('age', [18, 30])->get();
```

- `whereNotBetween`: 値が指定範囲外かをチェック
```php
$users = User::whereNotBetween('age', [18, 30])->get();
```

- `whereNull` / `whereNotNull`: カラムがNULLかどうかをチェック
```php
$users = User::whereNull('email_verified_at')->get();
```

### 集計関数
```php
// 件数を取得
$count = User::count();

// 最大値
$max = User::max('age');

// 平均
$avg = User::avg('age');

// 合計
$sum = User::sum('points');
```

### クエリの絞り込み

- `limit` と `offset` を使用して、件数やページを制御します。

```php
// 最初の10件を取得
$users = User::limit(10)->get();

// ページング（スキップしたい件数を指定）
$users = User::skip(10)->take(5)->get();
```

### 並び替え
```php
// 昇順で並び替え
$users = User::orderBy('name', 'asc')->get();

// 複数条件での並び替え
$users = User::orderBy('age', 'asc')->orderBy('name', 'desc')->get();
```

## リレーションシップの詳細

LaravelのEloquentは、データベースのリレーションシップを簡単に扱うためのメソッドを提供します。以下は、よく使うリレーションの詳細です。

### 1対多（hasMany）

```php
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}
```

- `hasMany`は、親モデルに対して複数の子モデルが関連付けられるリレーションです。

```php
// ユーザーの全ての投稿を取得
$user = User::find(1);
$posts = $user->posts;
```

### 多対1（belongsTo）

```php
class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
```

- `belongsTo`は、子モデルが親モデルに属していることを示します。

```php
// 投稿の作成者を取得
$post = Post::find(1);
$user = $post->user;
```

### 多対多（belongsToMany）

```php
class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}
```

- `belongsToMany`は、多対多のリレーションを表し、中間テーブルを使って複数のモデルを結びつけます。

```php
// ユーザーの全ての役割を取得
$user = User::find(1);
$roles = $user->roles;
```

### リレーションのデータ操作

- リレーションを使ってデータを追加・削除・更新することもできます。

```php
// 1対多リレーションに新しい投稿を追加
$user = User::find(1);
$user->posts()->create([
    'title' => 'New Post Title',
    'content' => 'Post content...'
]);

// 多対多リレーションに役割を追加
$user->roles()->attach($roleId); // 役割を追加
$user->roles()->detach($roleId); // 役割を解除
$user->roles()->sync([1, 2]); // 役割を同期（1,2以外は削除）
```

## ソフトデリートの詳細

ソフトデリートを使用すると、データベースからレコードを物理的に削除するのではなく、「削除済み」とマークして非表示にすることができます。

### ソフトデリートの設定
- モデルに `SoftDeletes` トレイトを追加します。

```php
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
    use SoftDeletes;

    // ソフトデリートに使用されるカラム
    protected $dates = ['deleted_at'];
}
```

### ソフトデリートの操作
```php
// ソフトデリート（物理的には削除されない）
$user->delete();

// ソフトデリートされたレコードも含む検索
$users = User::withTrashed()->get();

// ソフトデリートされたレコードのみ取得
$trashedUsers = User::onlyTrashed()->get();

// ソフトデリートを取り消す（復元）
$user->restore();
```

## その他の便利な機能

### スコープ（クエリの再利用）

- モデルでスコープを定義して、クエリを再利用できます。

```php
// モデル内でスコープを定義
public function scopeActive($query)
{
    return $query->where('active', 1);
}

// 使用例
$activeUsers = User::active()->get();
```

### アクセサ（データの整形）

- モデルの属性にアクセスする際に、自動的に整形するメソッドです。

```php
class User extends Model
{
    public function getFullNameAttribute()
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}

// 使用例
$user = User::find(1);
echo $user->full_name; // first_name と last_name を結合して表示
```

### ミューテータ（データの保存前に整形）

- モデルの属性を保存する前に、自動的に整形するメソッドです。

```php
class User extends Model
{
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
    }
}

// 使用例
$user = new User();
$user->password = 'plain-text-password'; // bcryptで自動的にハッシュ化
```

## JOINの詳細

LaravelのEloquentでは、データベースのテーブルを結合（JOIN）することができます。これにより、複数のテーブルからデータを取得することが容易になります。

### 内部結合（INNER JOIN）
- `join` メソッドを使用して、2つのテーブルを内部結合します。

```php
$users = DB::table('users')
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.*', 'posts.title')
    ->get();
```

この例では、`users` テーブルと `posts` テーブルを `users.id` と `posts.user_id` を基準に結合し、両方のテーブルからデータを取得します。

### 左外部結合（LEFT JOIN）
- `leftJoin` メソッドを使用して、左外部結合を行います。

```php
$users = DB::table('users')
    ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.*', 'posts.title')
    ->get();
```

左外部結合では、`users` テーブルの全てのデータが取得され、対応する `posts` のデータがない場合は `NULL` になります。

### 複数の条件でJOIN
- JOINに複数の条件を指定することも可能です。

```php
$users = DB::table('users')
    ->join('posts', function ($join) {
        $join->on('users.id', '=', 'posts.user_id')
             ->where('posts.active', '=', 1);
    })
    ->select('users.*', 'posts.title')
    ->get();
```

### クロス結合（CROSS JOIN）
- `crossJoin` メソッドを使用して、クロス結合（直積）を行います。

```php
$results = DB::table('sizes')
    ->crossJoin('colors')
    ->get();
```

クロス結合では、各サイズと各色のすべての組み合わせが返されます。

### 高度なJOINの例
- 複数のテーブルを同時にJOINすることもできます。

```php
$users = DB::table('users')
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->join('comments', 'posts.id', '=', 'comments.post_id')
    ->select('users.name', 'posts.title', 'comments.body')
    ->get();
```

この例では、`users`、`posts`、`comments`の3つのテーブルを結合し、それぞれのテーブルからデータを取得します。