Ray Lee | 李宗叡
Learn or Die
Published in
49 min readDec 9, 2020

--

Photo by Aaron Burden on Unsplash

# 前言

我喜歡使用 Laravel 開發的感覺, 除了開發快速, 程式碼簡潔且優雅之外, Laravel 框架本身也是一個很好的學習參照物。 本篇主要將官方文件重點整理成 Q&A 的形式呈現, 原子化的概念, 這方式並不適用於每個人, 但若對你有幫助, 我會很開心。

# 版本

Laravel 8.x

# 目錄

Laravel — 官方文件原子化翻譯 — 目錄

# Defining Models

以下的 Laravel command 的意思是?

  • Example:
php artisan make:model Flight
  • Answer: 建立一個名為 Flight 的 model

以下的 Laravel command 的意思是?

  • Example:
php artisan make:model Flight --migration

php artisan make:model Flight -m
  • Answer:
// 建立一個名為 Flight 的 model, 並建立其 migration
php artisan make:model Flight --migration

// 同上
php artisan make:model Flight -m

以下的 Laravel command 的意思是?

  • Example:
php artisan make:model Flight --factory
php artisan make:model Flight -f

php artisan make:model Flight --seed
php artisan make:model Flight -s

php artisan make:model Flight --controller
php artisan make:model Flight -c

php artisan make:model Flight -mfsc
  • Answer:
// 建立 Flight model, 並建立其 Factory
php artisan make:model Flight --factory
// 同上
php artisan make:model Flight -f

// 建立 Flight model, 並建立其 seeder
php artisan make:model Flight --seed
// 同上
php artisan make:model Flight -s

// 建立 Flight model, 並建立其 controlelr
php artisan make:model Flight --controller
// 同上
php artisan make:model Flight -c

// 建立 Flight model, 並建立其 migraiton, factory, seeder, 以及 controller
php artisan make:model Flight -mfsc

# Eloquent Model Conventions

Laravel 中, 假設 model name 為 AirTrafficController, 根據 Laravel Model Convention, table name 應為?

air_traffic_controllers

# Table Names

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
protected $table = 'my_flights';
}
  • Answer: 指定該 model 所對應的 table

# Primary Keys

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
protected $primaryKey = 'flight_id';
}
  • Answer: primary key 預設為 id, 可以特別指定

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
public $incrementing = false;
}
  • Answer: Laravel 預設 primary key 為 id, 且為 auto-incrementing, 會 cast 成 int, 若要使用 non-numeric 或 non-incrementing 的 primary key 的話, 要特別指定為 false

以下的 Laravel example code 的意思是?

  • Example:
<?php

class Flight extends Model
{
protected $keyType = 'string';
}
  • Answer: Laravel 預設 primary key 為 id, 且為 auto-incrementing, 會 cast 成 int, 若 primary key 不是 int, 需特別指定 type

# Timestamps

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
public $timestamps = false;
}
  • Answer: Laravel Eloquent 預設會自動管理 created_at 以及 updated_at 欄位, 若不需 Eloquent 自動管理, 可設為 false

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
protected $dateFormat = 'U';
}
  • Answer: Laravel 預設 timestamps 有其固定格式, 可特別指定格式, 格式決定儲存在資料庫中的格式以及 serialized 之後的格式

以下的 Laravel example code 的意思是?

  • Example:
<?php

class Flight extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'last_update';
}
  • Answer: Laravel 中, 預設儲存 timestamps 的 column 分別是 created_at 以及 updated_at, 可使用以上 example 來自定義

# Database Connection

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
protected $connection = 'connection-name';
}
  • Answer: Laravel 中, Eloquent Model 會使用預設的 Database connection, 可使用上面的 example 自定義

# Default Attribute Values

以下的 Laravel example code 的意思是?

  • Example:
<?php
class Flight extends Model
{
protected $attributes = [
'delayed' => false,
];
}
  • Answer: 設定 Eloquent Model attribute 的預設值

# Retrieving Models

# Adding Additional Constraints

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = App\Models\Flight::all();

foreach ($flights as $flight) {
echo $flight->name;
}
  • Answer: all() 可取得該 model 的所有 records, 也可使用 query constraints 之後, 使用 get() 取得結果

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = App\Models\Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();
  • Answer: where()->orderBy()->take() 為 constraints, 最後使用 get() 取得資料, 若無 constraints, 可直接使用 all() 取得資料

# Refreshing Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::where('number', 'FR 900')->first();

$freshFlight = $flight->fresh();
  • Answer: fresh() 會從 model 重新取得資料, 不影響 $flight 的內容

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::where('number', 'FR 900')->first();

$flight->number = 'FR 456';

$flight->refresh();

$flight->number; // "FR 900"
  • Answer: refresh() 會使用 fresh() 取得的 data 將原本的替換掉, 包括 relationship

# Collections

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = $flights->reject(function ($flight) {
return $flight->cancelled;
});
  • Answer: 將 cancelled 的 model 從 $flights 這個 collection 中移除, 並取代 $flights 也可使用
<?php
$flights->forget(function ($flight) {
return $flight->cancelled;
})

以下的 Laravel 中, 可以 foreach collection 嗎?

可以

# Chunking Results

以下的 Laravel example code 的意思是?

  • Example:
<?php
Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});
  • Answer: 會將 collections 分成 1 個 chunk 200 筆資料, 所以共有幾個 chunk 視乎該 collection 共有幾筆資料, 再將每個 chunk 丟入 closure 執行, 如此一來, 當處理資料數量龐大的 collection 時, 可節省記憶體單次調用量

以下的 Laravel example code 的意思是?

  • Example:
<?php
Flight::where('departed', true)->chunkById(200, function ($flights) {
$flights->each->update(['departed' => false]);
});
  • Answer: 一次只取 200 筆 update 以節省 memory, chunkById 會記住上一次 chunk 的 last_id, 並加上 orderById, 下一次只會從 last_id 之後取值; 若只使用 chunk 的話, 會是 offset … limit …, 後者遇到數據量大時, 效能會很差, 前者可以很明顯地增進效能

# Advanced Subqueries

以下的 Laravel example code 的意思是?

  • Example:
<?php
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
  • Answer:
<?php
// 新增 last_flight column, 其值為 query Flight table 得來
return Destination::addSelect(['last_flight' => Flight::select('name')
// 這行主要定義, 哪些 last_flight 會對應到哪一個 Destination row
->whereColumn('destination_id', 'destinations.id')
// 依照 arrived_at 排序
->orderBy('arrived_at', 'desc')
// 只取一筆, 即最近的航班
->limit(1)
])->get();

# Retrieving Single Models / Aggregates

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::find(1);

$flight = App\Models\Flight::where('active', 1)->first();

$flight = App\Models\Flight::firstWhere('active', 1);
  • Answer:
<?php
// 取得符合 primary key 的 model
$flight = App\Models\Flight::find(1);

// 取得符合 where constraint 的第一個 model
$flight = App\Models\Flight::where('active', 1)->first();

// where('active', 1)->first() 的縮寫
$flight = App\Models\Flight::firstWhere('active', 1);

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = App\Models\Flight::find([1, 2, 3]);
  • Answer: 取得 primary key 符合 array 的 model

以下的 Laravel example code 的意思是?

  • Example:
<?php
$model = App\Models\Flight::where('legs', '>', 100)
->firstOr(['id', 'legs'], function () {
// ...
});
  • Answer: 取得符合 (‘legs’, ‘>’, 100) 條件的第一個 model 的 ‘id’ 及 ‘legs’ column, 如果該 model 不可得, 則執行 closure 內的動作

# Not Found Exceptions

以下的 Laravel example code 的意思是?

  • Example:
<?php
$model = App\Models\Flight::findOrFail(1);

$model = App\Models\Flight::where('legs', '>', 100)->firstOrFail();
  • Answer:
<?php
// 取得 primary key 為 1 的 model, 如果沒找到, 則 throw 'ModelNotFoundException'
// 如果該 exception 沒有被 caught, 則會回傳 404 給 user
$model = App\Models\Flight::findOrFail(1);

// 取得符合 ('legs', '>', 100) 條件的第一個 model, 如果沒找到, 則 throw 'ModelNotFoundException'
// 如果該 exception 沒有被 caught, 則會回傳 404 給 user
$model = App\Models\Flight::where('legs', '>', 100)->firstOrFail();

# Retrieving Aggregates

以下的 Laravel example code 的意思是?

  • Example:
<?php
$count = App\Models\Flight::where('active', 1)->count();

$max = App\Models\Flight::where('active', 1)->max('price');
  • Answer:
<?php
// 取得符合 where('active', 1) 條件的 model 數量
$count = App\Models\Flight::where('active', 1)->count();

// 取得符合 where('active', 1) 條件的 model 中, price column 的最大值
$max = App\Models\Flight::where('active', 1)->max('price');

# Inserting & Updating Models

# Inserts

以下的 Laravel example code 的意思是?

  • Example:
<?php
namespace App\Http\Controllers;

class FlightController extends Controller
{
public function store(Request $request)
{
// Validate the request...

$flight = new Flight;

$flight->name = $request->name;

$flight->save();
}
}
  • Answer: 從 $request 取得 name, 在 assign 到 $flight model 的 name attribute, 在執行 save() 存到資料庫 created_at 以及 updated_at 會自動建立

# Updates

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::find(1);

$flight->name = 'New Flight Name';

$flight->save();
  • Answer: 取得 primary key 為 1 的 model, 再用 save() 更新其 name attribute, updated_at 欄位會自動更新

# Mass Updates

以下的 Laravel example code 的意思是?

  • Example:
<?php
App\Models\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
  • Answer: 取得符合 where(‘active’, 1), 以及 where(‘destination’, ‘San Diego’) 的 models, 並更新 delayed column 為 1

Laravel 中, 當使用 Eloquent 實施 mass update 時, model events 像是 saving, saved, updating, updated 會被觸發嗎?

不會

# Examining Attribute Changes

以下的 Laravel example code 的意思是?

  • Example:
<?php
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);

$user->title = 'Painter';

$user->isDirty(); // true or false
$user->isDirty('title'); // true or false
$user->isDirty('first_name'); // true or false

$user->isClean(); // true or false
$user->isClean('title'); // true or false
$user->isClean('first_name'); // true or true

$user->save();

$user->isDirty(); // true or false
$user->isClean(); // true or false
  • Answer:
<?php
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);

// 這裡變更了 $user model 的 title attribute, 但尚未更動資料庫
$user->title = 'Painter';

// $user model 的 title attribute 變了, 所以 true
$user->isDirty(); // true
// 同上
$user->isDirty('title'); // true
// first_name attribute 並未更動, 所以 false
$user->isDirty('first_name'); // false

// $user model 已有變更, 所以非 clean
$user->isClean(); // false
// title attribute 已變更, 所以非 clean
$user->isClean('title'); // false
// first_name attribute 並未更動, 所以 clean
$user->isClean('first_name'); // true

// 這邊才真正更動資料庫
$user->save();

// 更動後, model 跟資料庫已同步, 所以 isDirty 為 false
$user->isDirty(); // false

// 更動後, model 跟資料庫已同步, 所以是 clean 的
$user->isClean(); // true

以下的 Laravel example code 的意思是?

  • Example:
<?php
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);

$user->title = 'Painter';
$user->save();

$user->wasChanged(); // true or false
$user->wasChanged('title'); // true or false
$user->wasChanged('first_name'); // true or false
  • Answer:
<?php
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);

// 這邊更動了資料庫
$user->title = 'Painter';
$user->save();

// 資料庫在當次 request cycle 有更動, 故為 true
$user->wasChanged(); // true
// title 有更動, 故為 true
$user->wasChanged('title'); // true
// first_name 並沒有更動, 所以為 false
$user->wasChanged('first_name'); // false

以下的 Laravel example code 的意思是?

  • Example:
<?php
$user = User::find(1);

$user->name; // John
$user->email; // john@example.com

$user->name = "Jack";
$user->name; // Jack

$user->getOriginal('name'); // 這裡是?
$user->getOriginal(); // 這裡是?
  • Answer:
<?php
$user = User::find(1);

$user->name; // John
$user->email; // john@example.com

// 這裡變更了 $user model, 但尚未更動資料庫
$user->name = "Jack";
$user->name; // Jack

// 取得變更前的 $user model 的 name attribute
$user->getOriginal('name'); // John
// 取得變更前的 $user model
$user->getOriginal(); // 為更動前的 model array

# Mass Assignment

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

class Flight extends Model
{
protected $fillable = ['name'];
}
  • Answer: 允許 name column 可以批量 assign, 防止有心人士自帶預料外的參數 assign 到預料外的欄位

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::create(['name' => 'Flight 10']);
  • Answer: 建立一筆資料, 並取得該 model

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight->fill(['name' => 'Flight 22']);
  • Answer: assign ‘Flight 22’ 到 $flight model 的 name attribute 相當於 $flight->name = ‘Flight 22’;

以下的 Laravel example code 的意思是?

  • Example:
<?php
$fillable = [
'options->enabled',
];
  • Answer: 允許 nested JSON attribute “options->enabled” 可被批量 assign

以下的 Laravel example code 的意思是?

  • Example:
<?php
protected $guarded = [];
  • Answer: 該 model 內的所有 attribute 都允許 mass assignment

# Other Creation Methods

# firstOrCreate / firstOrNew

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::firstOrCreate(['name' => 'Flight 10']);

$flight = App\Models\Flight::firstOrCreate(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);

$flight = App\Models\Flight::firstOrNew(['name' => 'Flight 10']);

$flight = App\Models\Flight::firstOrNew(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
  • Answer:
<?php
// 使用條件 ['name' => 'Flight 10'] 從資料庫尋找, 若找到則回傳該 model,
// 若沒找到, 則使用 ['name' => 'Flight 10'] 建立該筆資料並回傳該 model
$flight = App\Models\Flight::firstOrCreate(['name' => 'Flight 10']);

// 使用條件 ['name' => 'Flight 10'] 從資料庫尋找, 若找到則回傳該 model,
// 若沒找到, 則使用 ['name => 'Flight 10', 'delayed' => 1, 'arrival_time' => '11:30']
// 建立該筆資料並回傳該 model
$flight = App\Models\Flight::firstOrCreate(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);

// 使用條件 ['name' => 'Flight 10'] 從資料庫尋找, 若找到則回傳該 model,
// 若沒找到, 則使用 ['name' => 'Flight 10'] 回傳並建立該 model, 但尚未
// 更新資料庫
$flight = App\Models\Flight::firstOrNew(['name' => 'Flight 10']);

// 使用條件 ['name' => 'Flight 10'] 從資料庫尋找, 若找到則回傳該 model,
// 若沒找到, 則使用 ['name => 'Flight 10', 'delayed' => 1, 'arrival_time' => '11:30']
// 建立該 model, 但尚未更新資料庫
$flight = App\Models\Flight::firstOrNew(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);

# updateOrCreate

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);
  • Answer:
<?php
// 使用條件 ['departure' => 'Oasland', 'destination' => 'San Diego'] 尋找
// 如果有找到, 更新 ['price' => 99, 'discounted' => 1], 如果沒找到, merge 上面
// 兩個 array 並建立該筆資料
$flight = App\Models\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);

以下的 Laravel example code 的意思是?

  • Example:
<?php
App\Models\Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
  • Answer:
<?php
// 尋找第一個 arg 中的兩筆 record [['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99], [array 2]]
// 如果沒找到, 則以上面 array 中的資料建立, 如果有找到, 即 duplicate record, 那就更新第三個 arg 中的
// price column, 則判斷是否 exist 的 unique 欄位為第二個 array 中的 ['departure', 'destination']
App\Models\Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);

# Deleting Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight = App\Models\Flight::find(1);

$flight->delete();
  • Answer: 取得 primary key 為 1 的 model, 並 delete

# Deleting An Existing Model By Key

以下的 Laravel example code 的意思是?

  • Example:
<?php
App\Models\Flight::destroy(1);

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

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

App\Models\Flight::destroy(collect([1, 2, 3]));
  • Answer:
<?php
// 刪除 primary key 為 1 的 model
App\Models\Flight::destroy(1);

// 同上
App\Models\Flight::destroy(1, 2, 3);

// 同上
App\Models\Flight::destroy([1, 2, 3]);

// 同上
App\Models\Flight::destroy(collect([1, 2, 3]));

以下的 Laravel example code, deleting 以及 deleted event 會被觸發嗎?

  • Example:
<?php
App\Models\Flight::destroy(1);

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

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

App\Models\Flight::destroy(collect([1, 2, 3]));
  • Answer: 會的, 因為 destroy 會分別載入每個 model, 並呼叫 delete method

# Deleting Models By Query

以下的 Laravel example code 的意思是?

  • Example:
<?php
$deletedRows = App\Models\Flight::where('active', 0)->delete();
  • Answer: 刪除符合 where(‘active’, 0) 的 model

以下的 Laravel example code, deleting 以及 deleted event 會被觸發嗎?

  • Example:
<?php
$deletedRows = App\Models\Flight::where('active', 0)->delete();
  • Answer: 不會, 因為實際上 model 並沒有被 retrieve

# Soft Deleting

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model
{
use SoftDeletes;
}
  • Answer: 啟用 soft delete, 啟用後當執行 delete(), model 並不會真正被刪除, 而是會在 deleted_at column 增加一筆時間, 如果 deleted_at column 不是 null, 那就代表該筆資料已被 soft deleted

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function up()
{
Schema::table('flights', function (Blueprint $table) {
$table->softDeletes();
});
}

public function down()
{
Schema::table('flights', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
  • Answer:
<?php
public function up()
{
// 增加 deleted_at column
Schema::table('flights', function (Blueprint $table) {
$table->softDeletes();
});
}

public function down()
{
// 刪除 deleted_at column
Schema::table('flights', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}

以下的 Laravel example code 的意思是?

  • Example:
<?php
if ($flight->trashed()) {
//
}
  • Answer: 確認該 model 是否被 soft deleted

# Querying Soft Deleted Models

# Including Soft Deleted Models**

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = App\Models\Flight::withTrashed()
->where('account_id', 1)
->get();
  • Answer: 當 model 被 soft deleted, 預設會被自動從 query 結果中排除, 如果要取得 soft deleted 的 model, 可以使用 withTrashed()

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight->history()->withTrashed()->get();
  • Answer: 取得 $flight model 的所有 history relation model, 包含 soft deleted

# Retrieving Only Soft Deleted Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flights = App\Models\Flight::onlyTrashed()
->where('airline_id', 1)
->get();
  • Answer: 只取得符合 where(‘airline_id’, 1) 條件的 soft deleted model

# Restoring Soft Deleted Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight->restore();
  • Answer: 將 $flight soft deleted model 復原, 換言之, 將 deleted_at column 設為 null

以下的 Laravel example code 的意思是?

  • Example:
<?php
App\Models\Flight::withTrashed()
->where('airline_id', 1)
->restore();
  • Answer: restore 符合 where(‘airline_id’, 1) 的所有 model, 即把 deleted_at column 設為 null

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight->history()->restore();
  • Answer: restore $flight model 的 relation history 上的所有 soft deleted model

# Permanently Deleting Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$flight->forceDelete();

$flight->history()->forceDelete();
  • Answer:
<?php
// 強制刪除 $flight, 即真正的刪除這筆資料
$flight->forceDelete();

// 強制刪除 relation history 上的所有 model, 這裡不包含 soft-deleted
// 如果要取得 soft-deleted 需加上 withTrashed()
$flight->history()->forceDelete();

# Replicating Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
$shipping = App\Models\Address::create([
'type' => 'shipping',
'line_1' => '123 Example Street',
'city' => 'Victorville',
'state' => 'CA',
'postcode' => '90001',
]);

$billing = $shipping->replicate()->fill([
'type' => 'billing'
]);

$billing->save();
  • Answer:
<?php
// 建立一筆資料, 並 assign 到 $shipping
$shipping = App\Models\Address::create([
'type' => 'shipping',
'line_1' => '123 Example Street',
'city' => 'Victorville',
'state' => 'CA',
'postcode' => '90001',
]);

// 複製 $shipping model, 將 type 替換為 'billing', 並 assign 到 $billing
// replicate 只是複製 model, 並未真正變動資料庫
$billing = $shipping->replicate()->fill([
'type' => 'billing'
]);

// 將 $billing 真正的存進資料庫
$billing->save();

# Query Scopes

Laravel 中, 當我新增 global scope constraint 時, 需要考慮到 soft-deleted 嗎?

不需要, Laravel 會自動處理好

# Global Scopes

# Writing Global Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class AgeScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('age', '>', 200);
}
}
  • Answer: 新增一個 global scope constraint, 可以在 model 的 booted method 中加入各種新增的 global scope constraint, 加入後, 該 model 取得的 query 都會自動附加 where(‘age’, ‘>’, 200) constraint

# Applying Global Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
protected static function booted()
{
static::addGlobalScope(new AgeScope);
}
}
  • Answer: 在 model 的 booted method 中, 可以將客制好的 global scope constraint AgeScope 附加到該 model, 如此一來, 之後使用 User model 的 query builder 都會自動附加 AgeScope 所定義的 constraint

# Anonymous Global Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
protected static function booted()
{
static::addGlobalScope('age', function (Builder $builder) {
$builder->where('age', '>', 200);
});
}
}
  • Answer: 利用 closure 來附加 global scope constraint, 這樣就不必另外定義一個 scope class, 適用於較簡單的 global scope

# Removing Global Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php
User::withoutGlobalScope(AgeScope::class)->get();
  • Answer: 從當次 query 的結果中, 移除 AgeScope 這個 global scope constraints

以下的 Laravel example code 的意思是?

  • Example:
<?php
User::withoutGlobalScope('age')->get();
  • Answer: 從當次 query 的結果中, 移除 age 這個 global scope constraints, age 為 closure 方式直接在 model 的 booted method 中定義的

以下的 Laravel example code 的意思是?

  • Example:
<?php
User::withoutGlobalScopes()->get();

User::withoutGlobalScopes([
FirstScope::class, SecondScope::class
])->get();
  • Answer:
<?php
// 從當次 User model 的 query 當中移除所有 global scopes
User::withoutGlobalScopes()->get();

// 從當次 User model 的 query 當中移除 array 中的 global scope
User::withoutGlobalScopes([
FirstScope::class, SecondScope::class
])->get();

# Local Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}

public function scopeActive($query)
{
return $query->where('active', 1);
}
}
  • Answer: 定義 local scope, 簡單來說, 當我使用 $query->popular() 就會等於 $query->where(‘votes’, ‘>’, 100), 而 $query->active() 便會等於 $query->where(‘active’, 1)

# Utilizing Local Scope

以下的 Laravel example code 的意思是?

  • Example:
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}

public function scopeActive($query)
{
return $query->where('active', 1);
}
}

$users = App\Models\User::popular()->active()->orderBy('created_at')->get();
  • Answer: popular() 以及 active() 為 local scope, 會使用定義於該 local scope 內 query

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}

public function scopeActive($query)
{
return $query->where('active', 1);
}
}

$users = App\Models\User::popular()->orWhere(function (Builder $query) {
$query->active();
})->get();
  • Answer: 相當於 $query->where(...)->orWhere(...) constraints, 只不過對象換成了 local scope, 像是 $query->popular()->orActive(), 注意後者語法只是比喻, Laravel 目前沒有提供這樣的用法, 也可使用 orWhere->

以下的 Laravel example code 的意思是?

  • Example:
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}

public function scopeActive($query)
{
return $query->where('active', 1);
}
}

$users = App\Models\User::popular()->orWhere->active()->get();
  • Answer: 相當於 $query->where(...)->orWhere(...) constraints, 只不過對象換成了 local scope, 像是 $query->popular()->orActive(), 注意後者語法只是比喻, Laravel 目前沒有提供這樣的用法, 也可使用 closure 方式帶入 orWhere()

# Dynamic Scopes

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
}

$users = App\Models\User::ofType('admin')->get();
  • Answer: dynamic scopes 概念, 可以動態的帶入參數到 scope 內, 所以 User::ofType('admin')->get(), 就相當於 User::where('type', 'admin')->get()

# Comparing Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
if ($post->is($anotherPost)) {
//
}
  • Answer: 比較兩個 model 是否有相同的 primary_key, table, database connection

以下的 Laravel example code 的意思是?

  • Example:
<?php
if ($post->author()->is($user)) {
//
}
  • Answer: 比較 $post model 的 author relation model 是否跟 $user model 有相同的 primary_key, table, database connection

# Events

Laravel Eloquent Model 中, retrieved event 什麼時候會被觸發?

當有一個現存 model 從 database 被 retrieve 時

Laravel Eloquent Model 中, creating/created event 什麼時候會被觸發?

當一個 model 第一次被儲存在資料庫時, 只有第一次會觸發

Laravel Eloquent Model 中, updating/updated event 什麼時候會被觸發?

當現存的 model 被更新且呼叫 save()

Laravel Eloquent Model 中, saving/saved event 什麼時候會被觸發?

當 model 被建立或更新都會觸發

# Using Closures

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
protected static function booted()
{
static::created(function ($user) {
//
});
}
}
  • Answer: 使用 closure 來定義當 created model event 被觸發後所做的事

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use function Illuminate\Events\queueable;

class User extends Model
{

protected static function booted()
{
static::created(queueable(function ($user) {
//
}));
}
}
  • Answer: 使用 closure 來定義當 created model event 被觸發後所做的事, 並 queue 被觸發的 closure listener

# Observers

以下的 Laravel example command 的意思是?

  • Example:
php artisan make:observer UserObserver --model=User
  • Answer: 建立一個 observer, 名為 UserObserver, 對應的 model 為 User model, 可定義一系列 User model 的各種 model event 的 Listener

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
public function created(User $user)
{
//
}

public function updated(User $user)
{
//
}

public function deleted(User $user)
{
//
}

public function forceDeleted(User $user)
{
//
}
}
  • Answer:
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
// 當 created model event 被觸發後要做的事
public function created(User $user)
{
//
}

// 當 updated model event 被觸發後要做的事
public function updated(User $user)
{
//
}

// 當 deleted model event 被觸發後要做的事
public function deleted(User $user)
{
//
}

// 當 forceDeleted model event 被觸發後要做的事
public function forceDeleted(User $user)
{
//
}
}

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Providers;

use App\Observers\UserObserver;
use App\Models\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
public function register()
{
//
}

public function boot()
{
User::observe(UserObserver::class);
}
}
  • Answer: 在 AppServiceProvider 中註冊 UserObserver, 註冊後 UserObserver 後, 定義於 UserObserver 的 Listener 會開始監聽 User model event

# Muting Events

以下的 Laravel example code 的意思是?

  • Example:
<?php
use App\Models\User;

$user = User::withoutEvents(function () use () {
User::findOrFail(1)->delete();

return User::find(2);
});
  • Answer: withoutEvent method 只接受 closure 為參數, 在這個 closure 內執行的任何 code 都不會觸發 model event 範例中刪除 primary key 為 1 的 User model, 但不會觸發任何 model event

# Saving A Single Model Without Event

以下的 Laravel example code 的意思是?

  • Example:
<?php
$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();
  • Answer: 修改 primary key 為 1 的 User model, 且不觸發任何 model event

--

--

Ray Lee | 李宗叡
Learn or Die

It's Ray. I do both backend and frontend, but more focus on backend. I like coding, and would like to see the whole picture of a product.