Laravel 通過子查詢建立動態關聯

sgm4231發表於2021-01-28

User 模型類中定義一個 lastPost 方法使其與該使用者最新發布的文章記錄建立一對一關聯關係:

public function lastPost()
{
    return $this->belongsTo(Post::class);
}

根據 Eloquent 預設使用的外來鍵關聯欄位名稱規則,上面的關聯關係對應的外來鍵欄位應該是 last_post_id(即 users 表中的 last_post_id 對映到 posts 表的 id 欄位建立關聯),如果是常規的關聯關係,需要在 users 表中包含 last_post_id,不過我們要建立的是執行時的動態關聯關係,這個「動態」不依賴於具體的資料表欄位,那要如何在執行時的 users 表中提供這個欄位呢,結合上面的子查詢實現,我們很容易想到,可以通過子查詢動態提供這個欄位。

我們繼續在 User 模型類中新增一個本地查詢作用域 scopeWithLastPost 方法來定義對應的子查詢實現邏輯:

public function scopeWithLastPost($query)
{
    return $query->addSelect([
        'last_post_id' => Post::select(['id'])
            ->whereColumn('user_id', 'users.id')
            ->where('status', Post::STATUS_NORMAL)
            ->orderByDesc('created_at')
            ->limit(1)
    ])->with('lastPost:id,title,user_id,created_at');
}

這裡我們將 posts 表子查詢欄位改為 id,將查詢得到的欄位別名設定為 users 表的 last_post_id,就可以在執行時動態建立 users 表的 last_post_id 欄位了,我們接著在查詢構建器上通過 with(‘lastPost’) 對 lastPost 關聯進行渴求式載入(這裡還指定了關聯查詢的查詢欄位),由於 users 表此時包含了 last_post_id 欄位,也就可以順理成章的進行對應的一對一關聯查詢了,這樣一來,就可以在使用該查詢作用域的 User 模型例項上獲取到與之關聯的 最新發布的一個 Post 模型例項了。

修改 UserController 關聯查詢程式碼如下:

class UserController extends Controller
{
    public function index()
    {
        $columns = ['id', 'name', 'email'];
        $users = User::select($columns)->withLastPost()->orderByDesc('id')->paginate(20);
        return view('user.index', ['users' => $users]);
    }
}

這一次,我們通過查詢作用域獲取動態的 lastPost 關聯關係,列印獲取到的 $users 變數,可以看到資料結構中包含了關聯的 lastPost 關聯物件,即 Post 模型例項:

Laravel 通過子查詢建立動態關聯
這一次,我們可以通過 $user->lastPost 物件獲取文章模型上指定的所有查詢欄位,不再是隻能獲取文章標題了

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章