Laravel CRUD實作(下)
Model
在上一篇的內容,有提到migration的建立與資料遷移。現在我們打開app\Entities\Post.php,在model的class內新增欄位,並給予欄位批量賦值的修飾,同時建立 user 方法,使 Post 能夠與 User 進行關聯:
app\Entities\User 新增關聯:
- 批量賦值:model可利用「create」方法將array型態的資料進行模型(實體)的新增,也就是說,$fillable 內都是允許「被填入值」的欄位
※當然,model內還有許多對欄位的屬性設定,比如指定model對應的資料表 (若未指定,會預設指向對應名稱的資料表,如:Post→posts),或者修改主鍵
View、Controller、Route的緊密相連
為何會一起講解畫面、路由與 controller 呢?因為當你指定某個 URI 來呼叫頁面或 API 時,路由檔會先檢查該 URI 是否被定義,有被定義的話則會執行該路由所指定 controller 的 function;若沒定義就會報錯。例如
建立控制器 (Controller)
※「–resource」是透過 Artisan 為 controller 建立所有符合 RESTful API 風格的 function
建立視圖
為了避免views資料夾因為頁面太多而雜亂,因此先在resources\views底下建立「post」資料夾,並在post資料夾內建立「index.blade.php」、「show.blade.php」、「create.blade.php」、「edit.blade.php」一共4個檔案,分別用來顯示文章列表、顯示單一文章、建立文章以及編輯文章
建立會員系統與畫面
- 這個指令會為我們建立 Laravel 內建的會員驗證功能(Auth),並且讓它先幫我們建立一個共同的layout。此時你會看到resources\views多了一個layouts資料夾,裡面有個「app.blade.php」,這檔案能夠當作許多頁面的「主視圖 (master page)」,也就是當作其他子視圖的共用模板,讓子視圖繼承它,這樣可以省下些許前端設計的麻煩。
- 副檔名「.blade.php」是讓這個檔案能使用Laravel的Blade模板,它能使畫面的開發上更加便利,且不需使用「<?php」的標籤
註冊使用者
來到 http://localhost:8000/register 註冊一個會員,便於後續操作
定義路由並套用 auth 中介層
routes\web.php 新增以下程式碼
- 利用Route的resource方法,依據PostController內的每個function,各自建立一支符合RESTful API的路由 (GET、POST、PUT/PATCH、DELETE),並以post作為路由前綴修飾,如:/post/create
- 可在command輸入「php artisan route:list」查看路由表,可以看見resource幫我們建立了所有function對應的路由
- 路由表可查看所有路由的 URI 與 name
- 我們讓post的所有路由,都經過auth的中介層來驗證身分是否合法 (是否登入),若未登入則被導向到登入畫面
建立 Repository
接著在app底下建立一個「Repositories」資料夾,並在Repositories資料夾中新增「PostRepository.php」,而這個檔案的用意為何呢?因為以往都會在 model 中撰寫 query 的邏輯,但現在我們將處理資料庫的邏輯,都交給了 Repository,這樣能夠使 controller 的程式碼更簡潔,而且避免因為過多 scope 而造成 model 的肥大。而上篇也有提到 entity 的部分,就是將 model 拆分為 entity 與 repository,分別進行資料表實體定義、資料存取邏輯的處理。
app\Repositories\PostRepository.php:
- namespace為宣告該檔案的命名空間,切記請勿打錯,否則會發生找不到檔案的錯誤
CRUD step1 - 文章列表&單筆文章顯示
編輯 app\Http\Controllers\PostController.php
- controller中,將PostRepository引入
- 利用protected定義$postRepo的屬性,讓這支 controller 能夠透過該屬性來調用PostRepository
- 「__construct」為 controller 類別的「建構函數」,意即這支 controller 的初始狀態,同時將PostRepository實例化為 postRepo 的物件,並指定給controller的postRepo屬性
- 「$this->postRepo->index()」為調用repository的index方法
- index function列出所有文章,並夾帶資料渲染回前端,讓前端得以使用blade進行處理
- show function是藉由路由傳入的id,找出該id的文章,並回傳給show頁面,若查無此文章則重新導向至文章列表
修改 PostRepository.php
- 利用 Post 取出文章,並將結果 return 給 controller
- find 是透過「主鍵」尋找資料
編輯index.blade.php:
- route('post.create') 與 view 的post.create不同!前者是導向由resource建立的「/post/create」,後者是回傳「post」資料夾的create頁面,請勿搞混
- extends是讓index.blade.php繼承layouts\app.blade.php的模板
- section是自定義的一個區塊,這邊將內容都放在content這區塊中,而在app.blade.php中,可藉由「@yield('content')」呼叫所有繼承它的子視圖中,名叫「content」的區塊
- 利用blade的@foreach,顯示controller回傳的datas變數中,各筆資料的所有欄位
編輯 show.blade.php
- $data->user->name 為透過 Post model 關聯到 User model,取得發文者姓名
- 使用html的form元素,導向至刪除文章的路由
- @csrf 為夾帶CSRF Token,讓後端得知該請求並非偽造請求
- @method('DELETE') 是夾帶DELETE方法,發送一個 DELETE 方法的 HTTP Request
- form元素的method屬性,僅支援GET、POST方法
CRUD step2 - 文章刪除
修改PostController.php的destroy function
- 藉由路由傳入文章id,並調用repository的delete方法進行刪除,最後重新導向至文章列表
於 PostRepository.php 新增 delete 方法
CRUD step3 - 新增文章
編輯 create.blade.php
- 藉由POST發送請求給伺服器
- 元素中的name屬性,用於讓後端辨識參數名稱
修改PostController的 create 及 store function
- 回傳view\post的create頁面
- store function中,將前端傳送的值由Request類別接收,並調用repository的create方法進行文章新增,最後重新導向至該文章的畫面
- $request 物件的 only 方法為限定只接收部分參數,此作法係避免接收到不必要或具有攻擊性的參數
於PostRepository建立create方法
- auth()->user() 為取得目前登入者的資訊 (User model),並使用建立好的「posts」關聯到 Post model,建立一筆文章,這樣就可以透過關聯的方式直接在 posts 資料表存入 user_id (發文者id)
- Model 的 create 方法所回傳的是一個模型,而update與destroy回傳的是true與false
CRUD step4 - 編輯文章
修改PostController的edit 與 update function
- edit function藉由路由傳入的id尋找文章,並回傳給edit頁面
- update function接收前端的值,並調用repository的update方法進行文章的更新,若更新失敗則跳轉至文章列表,若更新成功則跳轉至該文章頁面
於PostRepository建立update方法
編輯 edit.blade.php
- 透過form導向至文章更新的路由
- @method('PUT') 讓事件夾帶PUT方法傳送表單請求
- PUT/PATCH都是更新,但PUT是完整更新,PATCH是做部分更新
在URL輸入http://localhost:8000/post/至文章列表,測試剛剛建立的CRUD吧!