ThinkPHP6 多模型關聯查詢操作記錄

JiuJiuYeha發表於2024-04-28

新入職後組長安排了一個小的管理專案來檢驗能力,後發現自身對於 ThinkPHP 框架中的模型關聯屬於一竅不通,故被終止專案叫樓主去惡補 ThinkPHP6 框架知識。

對於多聯表查詢之前本人一直使用join方法,但是此方法對於程式碼效率和維護都有較大影響,故在此嘗試使用 ThinkPHP 框架內建的模型關聯來對多聯表進行操作(本次只記錄查詢操作)

一、建立資料表

首先我們先建立三個簡易的資料表 User、Article、Comment 並新增一些測試資料,結構如下:
User:
image
Article:
image
Comment:
image
其中 Article 表使用 user_id 與 User 表關聯;Comment 表使用 article_id 與 Article 表進行關聯。接下來我們來設定對應的資料庫模型程式碼。

二、建立對應資料表模型,並新增關聯

在 User 模型中,我們想實現根據提供的使用者 ID 查詢出該使用者對應的所有文章以及這些文章對應的評論

class User extends Model
{
    //主鍵
    protected $pk = 'user_id';

    //關聯文章
    public function articles(){
        return $this->hasMany(Article::class, 'user_id', 'user_id');
    }
    //根據文章關聯評論
    public function comments(){
        return $this->hasManyThrough(Comment::class, Article::class, 'user_id', 'article_id', 'user_id', 'article_id');
    }
}

由於 User 表與 Comment 表沒有直接的對應關係,所以我們使用 hasManyThrough() 方法來建立遠端模型關聯。其中 Comment 是我們要關聯的目標模型;Article 是中間模型;第一個 user_id 是中間模型外來鍵,第二個 article_id 是中間模型與目標模型關聯鍵,第三個 user_id 是當前模型的主鍵,第四個 article_id 是中間模型的主鍵。

接下來我們來設定 Article 模型的關聯關係,要求實現根據提供的 ID 查詢出該文章與所對應的所有評論

class Article extends Model
{
    //主鍵
    protected $pk = 'article_id';

    //關聯使用者
    public function user()
    {
        return $this->belongsTo(User::class, 'user_id', 'user_id');
    }

    //一對多關聯評論
    public function comments()
    {
        return $this->hasMany(Comment::class, 'article_id', 'article_id');
    }
}

最後我們還需要設定 Comment 模型

class Comment extends Model
{
    //主鍵
    protected $pk = 'comment_id';

    //關聯文章
    public function article()
    {
        return $this->belongsTo(Article::class, 'article_id', 'article_id');
    }
}

三、編寫控制器關聯查詢程式碼

由於是演示程式碼,所以暫時都在 index 控制器下編寫、同時我們預設所有的路由表已經配好

首先,我們來實現一個給出任意文章 ID 我們返回此 ID 的文章資訊同時返回該文章的所有評論的功能

public function article($id)
{
    $article = Article::with(['comments'])->find($id);

    return json_encode($article);
}

其中 with(['comments']) 對應我們在 Article 模型中建立的關聯方法,之後我們用 17 號文章請求這個介面,會得到如下資料:

{
  "article_id":17,
  "user_id":1,
  "title":"test2",
  "status":0,
  "comments":[
  {"comment_id":9,"article_id":17,"comment":"test comment 1","status":1},
  {"comment_id":10,"article_id":17,"comment":"test comment 2","status":1},
  {"comment_id":11,"article_id":17,"comment":"test comment 3","status":1}]
}

可以看到此時模型返回了 17 號文章資訊與該文章下所有的評論資訊。至此我們完成了一個一對多的雙表關聯查詢

接下來我們嘗試實現根據給出的使用者 ID 返回該使用者對應的所有文章以及這些文章所對應的所有評論

public function user($id)
{
    $user = User::with(['articles' =>function($query){
        $query->with(['comments']);
    }])->find($id);

    return json_encode($user);
}

此時我們先使用 with(['articles']) 關聯 Article 表來查詢文章,之後在 with() 方法內使用閉包來使 Comment 表與 Article 表進行關聯,這樣可以使查詢到的評論與文章之間是父子結構;接下來我們使用 2 號使用者請求這個介面,會得到如下資料:

{
  "user_id":2,
  "username":"test",
  "password":"123456",
  "articles":[
  	{"article_id":14,"user_id":2,"title":"test2","status":1,"comments":[]},
	{"article_id":15,"user_id":2,"title":"test3","status":1,"comments":[]},
	{"article_id":16,"user_id":2,"title":"test1","status":1,"comments":[
	  {"comment_id":6,"article_id":16,"comment":"test comment 1","status":1},
	  {"comment_id":7,"article_id":16,"comment":"test comment 2","status":1},
	  {"comment_id":8,"article_id":16,"comment":"test comment 3","status":1}]},
	{"article_id":19,"user_id":2,"title":"test1","status":1,"comments":[
	  {"comment_id":17,"article_id":19,"comment":"test comment 1","status":1},
	  {"comment_id":18,"article_id":19,"comment":"test comment 2","status":1},
	  {"comment_id":19,"article_id":19,"comment":"test comment 3","status":1}]},
	{"article_id":20,"user_id":2,"title":"test2","status":1,"comments":[
	  {"comment_id":20,"article_id":20,"comment":"test comment 1","status":1},
	  {"comment_id":21,"article_id":20,"comment":"test comment 2","status":1},
	  {"comment_id":22,"article_id":20,"comment":"test comment 3","status":1}]},
	{"article_id":21,"user_id":2,"title":"test3","status":1,"comments":[
	  {"comment_id":23,"article_id":21,"comment":"test comment 1","status":1},
	  {"comment_id":24,"article_id":21,"comment":"test comment 2","status":1},
	  {"comment_id":25,"article_id":21,"comment":"test comment 3","status":1}]}]
}

可以看到這樣直接查詢出了所有與使用者對應的文章以及這些文章所對應評論,同時表與表之間的資料是有父子關係的。
而當我們不使用閉包函式,而是直接在 with() 方法內直接呼叫我們在 User 模型中定義的遠端關聯 Comment 會返回什麼樣的資料呢?此時我們修改一下控制器中的程式碼

$user = User::with(['articles', 'comments'])->find($id);\\刪除語句中的閉包

此時我們再次拿同樣的 ID 請求這個介面,會得到如下資料:

{
  "user_id":2,
  "username":"test",
  "password":"123456",
  "articles":[
  	{"article_id":14,"user_id":2,"title":"test2","status":1},
	{"article_id":15,"user_id":2,"title":"test3","status":1},
	{"article_id":16,"user_id":2,"title":"test1","status":1},
	{"article_id":19,"user_id":2,"title":"test1","status":1},
	{"article_id":20,"user_id":2,"title":"test2","status":1},
	{"article_id":21,"user_id":2,"title":"test3","status":1}],
  "comments":[
	{"comment_id":6,"article_id":16,"comment":"test comment 1","status":1},
	{"comment_id":7,"article_id":16,"comment":"test comment 2","status":1},
	{"comment_id":8,"article_id":16,"comment":"test comment 3","status":1},
	{"comment_id":17,"article_id":19,"comment":"test comment 1","status":1},
	{"comment_id":18,"article_id":19,"comment":"test comment 2","status":1},
	{"comment_id":19,"article_id":19,"comment":"test comment 3","status":1},
	{"comment_id":20,"article_id":20,"comment":"test comment 1","status":1},
	{"comment_id":21,"article_id":20,"comment":"test comment 2","status":1},
	{"comment_id":22,"article_id":20,"comment":"test comment 3","status":1},
	{"comment_id":23,"article_id":21,"comment":"test comment 1","status":1},
	{"comment_id":24,"article_id":21,"comment":"test comment 2","status":1},
	{"comment_id":25,"article_id":21,"comment":"test comment 3","status":1}]
}

可以看到雖然也都查詢出了所有資料,但是文章與評論之間並不是父子關係而是同級關係。

至此雙表與三表的多表之間模型關聯查詢的程式碼已經介紹演示完畢,具體的應用場景需要讀者們根據自身的業務場景來具體處理;本文章僅代表個人的學習經驗,具體程式碼與引數設定請參考ThinkPHP官方開發文件。

第一次寫部落格記錄學習過程,如有錯誤還請大佬們多多指出。

相關文章