ORM簡單介紹

在Laravel中,ORM的主要工具是Eloquent。Eloquent提供了一種直覺式的方法來操作資料庫,讓資料表和模型之間建立了一對一或一對多的映射關係。以下是一些ORM操作的基本用法。

ORM資料種類

  • Laravel撈資料幾種類型:

    1. ORM:Eloquent 模型,可以$data->$field和$data[$field],有getter,setter
    2. QueryBuilder:關連數組(ArrayAccess),只能$data->$field,也有getter,setter(僅限一維以下才有,因為是stdClass)
  • Laravel兩種常用特別的資料格式:

    1. Collection: Laravel內建物件,有很多內建用法,但是存取資料基本上以陣列索引訪問為主
      1
      2
      $a = ['a' => 123];
      $a = collect($a);
    2. StdClass: PHP原生的物件,簡單來說就是讓資料可以對象屬性訪問
      1
      2
      $a = ['a' => 123];
      $a = (object) ($a);

使用ORM基本觀念

  1. 使用create、update、fill(批量賦值)時,要先設定fillable(白名單)或guarded(黑名單),否則會無法寫入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    protected $fillable = [
    'field1',
    'field2',
    ];

    protected $guarded = [
    'field3',
    'field4',
    ];

ORM常見用法

撈資料常用方法

  1. where常用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    // 基本用法
    $query->where('id', '1');

    // 如果是多個條件,可以使用陣列表示
    // 第一種寫法
    $query->where([
    ['id', '1'],
    ['date', '<=', date("Y-m-d H:i:s")]
    ]);

    // 第二種寫法
    $query->where([
    ['id' => '1'],
    ['date' => '<=', date("Y-m-d H:i:s")]
    ]);

    // 如果要把多個條件括號起來,需使用閉包
    $query->where(function ($query) {
    $query->where('created_at', '>=', date("Y-m-d H:i:s"))
    ->orWhereNull('created_at');
    });

    // 如果要多括號條件,可以使用陣列放閉包(可多個)
    $query->where([
    ['id', '1'],
    ['date', '<=', date("Y-m-d H:i:s")],
    function ($query) {
    $query->where('created_at', '>=', date("Y-m-d H:i:s"))
    ->orWhereNull('created_at');
    }
    ]);

    // 一次撈出多筆資料
    $query->whereIn('id', [1, 2, 3, 4]);

    // 一次撈出多筆資料,例如:一次撈出id為1~10的資料
    $query->whereBetween('id', [1, 10]);

    // 一次撈出多筆資料,例如:一次撈出id不為1~10的資料
    $query->whereNotBetween('id', [1, 10]);

    // 一次撈出多筆資料,例如:一次撈出沒有created_at的資料
    $query->whereNull('created_at');

    // 一次撈出多筆資料,例如:一次撈出有created_at的資料
    $query->whereNotNull('created_at');

    // 一次撈出多筆資料,例如:一次撈出有關聯資料的資料
    $query->whereHas('comments');

    // 一次撈出多筆資料,例如:一次撈出沒有關聯資料的資料
    $query->whereDoesntHave('comments');
  2. 其餘方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    // 只撈出特定欄位
    $resource = $query->select('id');

    // 沒有限制撈取欄位,只影響取出資料的格式
    $resource = $query->pluck('id');

    // 只撈出資料筆數
    $resource = $query->count();

    // 只撈出是否有資料
    $resource = $query->exists();

    // 只撈出特定欄位的最大值
    $resource = $query->max('id');

    // 只撈出特定欄位的最小值
    $resource = $query->min('id');

    // 只撈出特定欄位的平均值
    $resource = $query->avg('id');

    // 可將資料轉為QueryBuilder
    $resource = $query->toBase();

    // 可將資料分批撈出
    $query->chunk(100, function ($resource) {
    foreach ($resource as $value) {
    // do something
    }
    });

    // 可在操作資料時,做額外的動作
    $query->tap(function ($query) use ($request) {
    if ($request->has('search') && $request->search != '') {
    $query->where('title', 'like', '%' . $request->search . '%');
    }
    });

    // 可拿到與comments關聯的post資料
    $posts = App\Post::has('comments')->get();

    // 跟上面不同的是,這個是拿到comments資料
    $comments = $post->comments;

    // 可拿到與comments沒有關聯的post資料
    $posts = App\Post::doesntHave('comments')->get();

    // 與doesntHave很像,但是這可以使用where條件(第二參數也可帶閉包)
    $resource = $query->whereDoesntHave('comments');
  3. 善用with,可以一次撈出多筆資料,例如:一次撈出user、profile、posts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 這樣寫會有N+1問題
    $users = User::all();

    foreach ($users as $user) {
    echo $user->profile->name;
    echo $user->posts->title;
    }

    // 這樣寫就不會有N+1問題
    $users = User::with(['profile', 'posts'])->get();

    foreach ($users as $user) {
    echo $user->profile->name;
    echo $user->posts->title;
    }

    # with其他用法

    // 一次撈出多個關聯資料
    $query->with(['data', 'data2']);

    // 一次撈出多個關聯資料(包含軟刪除資料)
    $query->withTrashed(['data', 'data2']);

CUD常用方法

  1. create、update、delete常用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 基本用法
    $model->create([
    'field1' => 'value1',
    'field2' => 'value2',
    ]);

    // 基本用法
    $model->update([
    'field1' => 'value1',
    'field2' => 'value2',
    ]);

    // 基本用法
    $model->delete();

    // 基本用法
    $model->forceDelete();

    // 基本用法
    $model->restore();
  2. 假捨想要無視批量賦值的限制,可以使用forceFill、forceCreate、forceUpdate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $model->forceFill([
    'field1' => 'value1',
    'field2' => 'value2',
    ]);

    $model->forceCreate([
    'field1' => 'value1',
    'field2' => 'value2',
    ]);

    $model->forceUpdate([
    'field1' => 'value1',
    'field2' => 'value2',
    ]);
  3. 複製資料

    1
    2
    3
    4
    5
    // 基本用法
    $model->replicate();

    // 基本用法
    $model->replicate()->save();
  4. 使用create、update、delete時,會自動更新updated_at欄位,如果不想要更新,可以使用updateTimestamps(),但是要注意,這個方法會把created_at、updated_at都設為null

    1
    2
    $model->updateTimestamps();
    $model->save();

其餘常用方法

  1. 要把撈出的資料刪除,一樣使用迴圈unset
    1
    2
    3
    foreach ($resource as $key => $value) {
    unset($resource[$key]);
    }