你好,歡迎回到 Laravel 百萬年薪特訓營
之前花了不少時間介紹如何建立表格與假資料
終於到了介紹如何去運用這些資料的單元
我將要告訴你如何優雅地去實作表格的 CRUD 功能
也就是透過 Eloquent 來完成
不需要你自己去寫 SQL 語法
我要教給你的這些技巧每一個都很實用
請你調整好自己的狀況
跟著我一起學會撰寫 CRUD 程式吧
[換頁]
老規矩,為了幫你進入狀況
我還是幫你做個 CRUD 快速入門
但為了避免影片長度過長
我就挑重點講就好
[換頁]
有些人或許不知道什麼是 CRUD
其實它代表的是我們後端工程師最基本必須要會
存取資料庫表格的四個動作
分別是新增 CREATE
查詢 READ
修改 UPDATE
以及刪除 DELETE
取這四個單字的頭,就成了 CRUD
[換頁]
而 CRUD 是有對應到 Restful 的路由規則的
我們在介紹控制器的單元有談過這張表格
如果你對這個表格不熟悉的話
建議你回去重看控制器介紹的單元
這邊只是要提醒你
當實做這七個方法時就要用到 CRUD 技巧
[換頁]
這張投影片只是提醒你 CRUD 對應 RESTful 的懶人包
如何在生成 Controller 之時順便生成 RESTful 方法
以及宣告 CRUD 所需要的路由規則
同樣是在介紹控制器單元有完整說明
這裡只是加深你的印象
[換頁]
之前我們有完整的介紹過什麼是 Restful
它有一個特徵是這個
是一種純粹使用 URL 網址來傳遞資訊的機制
比如 /photos/1/edit
就傳遞了三個訊息
第一 針對 photos 表格做處理
第二 取出主鍵欄位為 1 的資料
第三 開啟編輯該筆資料的頁面
[換頁]
剛剛已經複習過 CRUD 方法與路由規則生成的懶人包
也是我最多使用的做法
但有些情況下你可能需要個別的去宣告路由規則
這裏我也補充說明一下
在路由規則介紹單元我們有提過
在指定某請求要交由哪個控制器的方法來接手
它的格式就是控制器@方法名稱
在 8.x 以上版本控制器名稱前面必須要補上完整命名空間
畫面上顯示的這個語法
你或許看起來有點陌生
但他其實只是一種替代語法把第二參數變成了陣列
這樣就能夠在指定所要負責的控制器方法之餘還為此路由命名
但你仍舊可以用之前在路由規則宣告單元所教的做法去撰寫
不一定要這樣寫
這裡只是讓你了解有這種寫法
陣列的 uses 鍵用來指定控制器方法
而 as 鍵則用於為路由命名
而路由命名慣例上喜歡用資源名.動作的格式
比如這裡的 tasks.store
[換頁]
當我們完成 CRUD 作業之後都會需要做畫面的跳轉
比如當你完成某筆資料變更的動作
就會需要跳轉到該筆資料的顯示頁面或者是表格的總覽頁
如果不這麼做,就會看到畫面一片白色
有時甚至會導致該動作被執行多次
資料變更還算好
當執行資料新增時就會導致新增多筆相同資料
所以請務必記得要做轉址的動作
轉址方法就是用畫面上的這個語法
我們之前在轉址單元就已經介紹過了
[換頁]
首先來介紹該如何新增資料
[換頁]
第一種用 Model 新增資料的方法
就是在建立 Model 類別物件並設定屬性後
去呼叫它的物件方法 save()
這時物件的狀態就會和資料庫同步
達到新增資料的目的
寫法分兩種
一種是畫面左邊這樣用屬性來進行設定
另一種則是畫面右邊這樣用建構子來設定
結果沒什麼不同
你可以根據自己的喜好來選擇
有個小細節要注意
如果你選擇使用屬性來設定的話
在用 new 保留字去生成物件時是可以不需要加上小括號的
像這樣
[換頁]
第二種用 Model 新增資料的方法
這個更為常用
因為你可以從控制器函式所給你的 Request 物件
取出各欄位資料後
接著用 create() 來新增資料
來看畫面的這段程式碼你就明白了
store 方法負責將資料新增到資料庫內
因此該方法會用到 Request 物件
可以從參數列取得
Request 物件的 all() 能得到所有傳入的欄位資料陣列
將欄位資料陣列傳入模型的 create() 完成新增資料動作
[換頁]
接著我有必要談談最困擾新手的一個錯誤
MassAssignment Exception
到底什麼是 MassAssignment?
又為什麼 Laravel 要設計這樣的機制呢?
現在我來解決你的這些困擾
Mass Assignment 照字翻是大量複值
但它指的其實是
你直接把從前端所傳入的資料以陣列直接丟給模型 create() 的行為
像第一種做法雖然也有用到陣列但透過建構子生成就不算
至於 Laravel 設計這個機制的原因
當然就是安全考量
從前端取得傳入資料有很多種做法
其中 all() 是最簡單也最危險的作法
你能得到所有的傳入資料當然也包含別人多加給你的
如果有駭客熟知你的表格結構與程式碼
就能夠透過竄改網址的方式來追加欄位資料
在你不知情的情況下去異動不該被修改的欄位
比如使用者權限
因此 Laravel 在發現你正在做 MassAssignment 時
預設所有欄位都是不可以寫入的
需要你自行告訴它哪些可以寫入
甚至你還可以自己去
關閉某個模型類別的 Mass Assignment
雖然在使用模型的 create() 需要注意大量賦值的問題
但它仍然是很好用的
因為可利用它來快速新增資料
只要注意陣列的鍵與欄位名稱有對應到即可
所以一般我們會讓前端表單的 name 與資料庫表格欄位一致
就可以輕易地利用 create() 來新增資料了
至於 Mass Assignment 的問題你只需要透過白黑名單來解決即可
[換頁]
什麼是白名單,什麼又是黑名單呢?
白名單是指哪些欄位可透過 Mass Assignment 來寫入
黑名單則是相反
剛才有說過 Laravel 預設是把所有欄位都放進黑名單
因此要開放欄位可寫入你就需要把合法的欄位放進白名單中
[換頁]
具體的作法請看這張投影片
我們需要在模型類別裡頭加入保護級的 fillable 屬性
fillable 的內容是陣列
讓你加入可合法被寫入的欄位名稱
如果你懶的逐一列出要放行的欄位
你也可以直接複寫 guarded 屬性
將之設定為空陣列
黑名單為空就意味著不再對此模型進行任何大量賦值保護
寫起來更為方便但也就失去了安全性
假如可以的話
建議你還是以白名單的方式來個別開放比較好
[換頁]
接著來說明如何查詢資料
[換頁]
首先先看該如何查詢單筆資料
只要你有保留每個表格的主鍵欄位
你就能夠使用這幾個方法來找出需要的資料
透過模型的 find() 只要傳入主鍵 id
就能得到對應該主鍵值的資料
如果找不到資料的話就會回傳 null
如果在 find 後面加上 OrFail 後綴的話
就代表當找不到該主鍵資料的話
程式就會直接報錯而不是回傳 null
除了用 find 會得到單筆資料之外
還有一種情況也只會得到單筆資料
那就是在下完查詢條件之後用 first() 來進行時
不管查到幾筆資料最終你只會得到第一筆資料
當然也就符合查詢單筆資料
這三個方法最後回傳給你的一定會是模型物件
你可以直接取用他們的屬性
[換頁]
我知道你剛看到 where()
還不太清楚裡頭的機制
所以這張投影片我想好好的和你聊聊
在 Eloqeunt 世界中的資料查詢之旅
先來看這整段程式碼
我們為 Task 模型去加入 is_feature 欄位須為 true 這限制條件
接著用 orderBy() 來將查詢結果用 created_at 進行從新到舊排序
最終寫上 get() 來完成查詢
然後我們將查到的結果存入名為 tasks 的變數
你應該在網路上見過像這樣的程式碼
但你或許不曉得在這段查詢資料的旅途中
到底發生了什麼
而如果旅途在過程中結束的話
到底 $tasks 又會得到了什麼
在整個資料查詢的旅程當中簡單可分成兩個階段
分別是 SQL 語句建構
以及向資料庫進行查詢
Eloquent 向資料庫進行查詢並沒有什麼黑科技
同樣是透過 SQL 語法
這就是為什麼我花了一些單元向你介紹 SQL 語法的原因
只是你不用自己寫罷了
當你呼叫這個階段的相關函式
比如這個例子中的 where() 和 orderBy()
所得到的回傳內容就會是查詢建構器
或稱為 QueryBuilder
一旦你明白了這點
就能夠做出搭配條件判斷式
透過多行程式碼來完成一個 SQL語法建構的進階用法
而一旦呼叫完 get() 之後
就會結束 SQL 語句建構階段
開始向資料庫進行查詢
而旅途是不可逆的
你只能夠省略 SQL 語句建構階段
代表你是要查詢該表格的所有資料
但你不可以在進行查詢之後回頭去做 SQL 語句建構的動作
因為你得到的已經是資料集合
它們不再具備建構 SQL 語句的能力
了解這些原則將能讓你明白到底 $tasks 變數內的東西是什麼
這能夠對你撰寫查詢程式碼時起到關鍵作用
[換頁]
談完資料查詢之旅我們繼續來看如何查詢多筆資料
當你想要查詢表格的所有資料有兩種方法
第一是透過專有的 all()
第二種則是更為泛用的 get()
雖然 get() 是用來就查詢條件進行查詢
但如果不下任何條件的話不就等於查詢表格的所有資料嗎
所以我個人更偏愛使用 get() 來進行全表查詢
當你需要加入限制條件時
最常用的肯定就是 where()
where() 最常用的是兩個參數的版本
第一個參數是要查詢的欄位名稱
第二個參數則是該欄位所要限定的值為何
條件為相等
如果你想比較的並非相等而是其他比如大於或小於
就可以改寫成 三個參數的版本
這個時候第二個參數就變成比較運算子
第三個參數才是該欄位所要限定的值為何
有需要你在網路上可以找到更多的內容
另外 where() 並非只能寫一個
你當然可以組合多個 where() 來達到交集的過濾條件
也就是 SQL 語法中的 AND
當條件下完之後別忘了補上 get() 來進行查詢
你還可以在 get() 之前搭配 orderBy() 來進行資料排序
第一參數為排序的依據欄位
第二參數則是從大到小還是從小到大
比如這個例子中是根據 created_at 欄位,從大到小排序
更口語化的說就是從新排到舊
有個原則請你一定記起來
當你使用 get() 或 all() 這種有可能得到多筆資料的查詢方式
不管最終結果是一筆或多筆資料
只要有可能是多筆資料
你得到的必然是物件集合,你需要先取出資料物件後才可以去取欄位資料唷
[換頁]
這個頁面我幫你整理出一些可以使用的限制方法
where() 剛才介紹過
orWhere() 則是讓你組合出聯集的條件語法
也就是 SQL 中的 OR
whereBetween 適合針對欄位內容為數值的過濾條件
比如使用者年紀介於 18 到 35 歲之間就很好用
whereIn 讓你比對欄位資料需為條件陣列中的某一個
比如限定使用者住在台北或新北市就能用這個
whereNull 與 whereNotNull 比對某欄位是否為空值
如果你偏愛直接寫 SQL 語法
那 whereRaw 就是你在找的方法
distinct 函式就跟同名的 SQL 語法相同用法
[換頁]
這一頁我幫你整理出查詢的修改方法
orderBy() 剛才介紹過,用來做資料排序
groupBy() 與 having() 多用於資料分析與統計
讓你能根據欄位名稱來進行分群再針對這些群組設定搜尋條件
skip() 設定要跳過多少筆資料
take() 則決定要回傳幾筆資料
這兩個函數組合在一起就能做出分頁功能
latest() 和 oldest() 用來做時間排序,和 orderBy() 差不多
我個人都用 orderBy 來做
最後的 inRandomOrder() 可以隨機排序結果
做賓果遊戲可能會比較好用
[換頁]
之前課程有人問過我該如何使用 groupBy() 和 having() 來做分群查詢
所以我補了這張投影片給你們參考
但我必須說明分群查詢是比較資深的工程師要做分析報表才會使用的技巧
當你還在入門階段搞不太懂也不需要太過在意
之後有用到再回來看即可
如果你連分群的 SQL 語法都看不懂
那這個投影片你可以先跳過
select() 能讓你去指定要取得哪些欄位
和 SQL 語法一樣
如果你用的是 Eloquent 模型類別
需要先呼叫 getQuery() 來取得底層查詢建構器
如果你想直接撰寫原生 SQL 語法可以搭配 raw()
還有一個 havingRaw() 能讓你撰寫原生的 having 語法
[換頁]
這邊我同樣幫你整理出所有的進行資料庫查詢語法
它們多半會串在查詢程式碼的最後
get() 剛說過,最泛用的一個,一定要記起來
all() 取得所有資料,沒 get() 好用
first() 和 firstOrFail() 取得第一筆資料
find() 和 findOrFail() 用主鍵來進行查詢
value() 只從第一列的指定欄位取值
我很少用到
min() 與 max() 用來回傳特定欄位的最小或最大值
sum() 回傳特定欄位所有值的總和
avg() 回傳特定欄位所有值的平均值
with() 同時回傳所參考的資料
這個如果不懂關聯的話就不太好懂
等到表格間關聯的查詢章節再來好好說明
[換頁]
接下來談談該怎麼修改與刪除資料
[換頁]
一般在修改資料時
最常見的情境就是從 request 物件取得欄位資料後
接著用 Model 物件的 save() 來進行同步更新
比如這段範例碼
先用主鍵欄位 id 搭配 find() 來找出資料後
設定該資料的 is_feature 欄位的值為前端所傳入的同名輸入項的值
這時只是改變模型物件的值
實際資料庫沒有任何變化
但是當你呼叫該模型物件的 save() 之後
就會啟動 Active Record 的第三個特性
物件可管理自己的持久保存
白話說就是這時資料庫資料的狀態就會和物件屬性完成同步
最終達到變更資料的目的
[換頁]
這裡順便補充一個組合技給你
之前在路由定義單元有介紹過 Route Model Binding
它能讓你少寫一個用主鍵來進行查詢的程式碼
因此在這時你不論是用在修改資料或者是等會要說的刪除資料
都極為好用
實際上預設懶人包所生成的 CRUD 方法
都是使用這樣的組合技的
雖然並非必要,但我很推薦你把這個技巧給學起來
如果還是不熟 Route Model Binding
請你回到路由定義章節去再看一次
[換頁]
當你要刪除資料時有兩種方式
這裡先介紹當你已經取得該資料的模型物件時
你可以直接呼叫該物件的 delete() 來進行刪除
就如同這段範例這樣
直接用 Route Model Binding 取得該資料物件後
呼叫 delete() 完成資料刪除
刪除完之後別忘了轉址到其他路由以免畫面是一片白色
[換頁]
假如你沒有該資料的物件
但是有一個或多個主鍵的id
你還是可以利用 Model 模型類別的 destroy() 來進行刪除
就像是畫面上這樣
[換頁]
這個單元的內容與知識點都非常的多
我已經盡量濃縮精華觀念給你了
我建議你至少看個兩次以上來掌握這些觀念
並一定要多加練習才有辦法靈活運用
請你花一點時間來完成這些作業
1.為你的作品網站生成對應 Controller,並生成 RESTful 資源函式
2.試看看將所有函式改成支援 Route Model Binding 的寫法
3.為資源函式加入 CRUD 的實作程式
4.確保模型類別有加入 fillable 屬性,並開放除 id 外所有欄位通過 Mass Assignment 機制
5.為 web.php 加入測試路由來測試 CRUD 能否正常執行
[換頁]
你已經堅持到這裡了 表示你非常的棒
再接再厲 很快你就會完成 Laravel 入門了
我們下個單元見 掰掰