如何寫一個屬于自己的數(shù)據(jù)庫封裝(11) - 關聯(lián)關系篇

上一期 如何寫一個屬于自己的數(shù)據(jù)庫封裝(10) - 自動載入篇
下一期 如何寫一個屬于自己的數(shù)據(jù)庫封裝(12) - 分頁篇

開始之前

早在查詢 - JOIN篇內我們就已經基于數(shù)據(jù)庫 JOIN 命令 實現(xiàn)了相關的實用函數(shù), 但美中不足的是, 調回的數(shù)據(jù)僅限于讀 (Read Only), 無法對副表記錄進行寫操作, 因此本期將會對此做出補充, 加強封裝包的可用性.

本期核心概念基于Laravel原代碼, 但僅實現(xiàn)最常用的3種函數(shù), 其余請自行實現(xiàn).

Builder.php

  • hasOne - 一對一關聯(lián)
public function hasOne($model, $foregin, $primary) {
        // 實例化 $model 中所代表的數(shù)據(jù)庫表, 但必須先在 model 文件夾內設置該表的模型
        $new = new $model();
        // 獲取數(shù)據(jù)庫表的名字
        $table = $new->getTable();
        // 將當前 model 轉為上方實例化的 Model
        $this->model = new $model();
        // join 函數(shù)連接副表返回數(shù)據(jù)
        return $this->select(["$table.*"])->join($table, $foregin, $primary);
    }
  • hasMany - 一對多關聯(lián)
// 實現(xiàn)原理同 hasOne()
public function hasMany($model, $foregin, $primary) {
    $new = new $model();
    $table = $new->getTable();
    $this->model = new $model();
    return $this->select(["$table.*"])->join($table, $foregin, $primary);
}
  • hasManyThrough - 一對多間接關聯(lián)
/**
     * 兩個關聯(lián)的表之間相隔著一個收錄了它們的主鍵作為副鍵的表
     * @param  Model  $model1   中間的表
     * @param  Model  $model2   最終想查詢的表
     * @param  string  $foregin1  當前表的主鍵在中間表內作為副鍵的字段名
     * @param  string  $primary1 當前表的主鍵
     * @param  string  $foregin2 中間表的主鍵在最終表內作為副鍵的字段名
     * @param  string  $primary2 中間表的主鍵
     * @return Builder           Builder實例
     */
public function hasManyThrough($model1, $model2, $foregin1, $foregin2, $primary1, $primary2) {
        // 帶入當前實例的 model 待用
        $model = $this->model;
        // 實例化 model1
        $model1 = new $model1();
        // 實例化 model2
        $model2 = new $model2();
        // 獲取 model1 的表名
        $table1 = $model1->getTable();
        // 獲取 model2 的表名
        $table2 = $model2->getTable();
        // 由于最終想操作的實例是 model2, 設置 model2 為 實例的 model
        $this->model = $model2;
        // join 函數(shù)連接三個表
        return $this->select(["$table2.*"])
                    ->join($table1, $foregin1, $primary1)
                    ->join($table2, $foregin2, "$table1.$primary2");
}

上方的函數(shù)如果看不懂沒關系, 下方的例子可以簡單直白的告訴你這些函數(shù)有什么用

例子

  1. 一對一

一部電影僅有一個語種(場景需要,勿糾結), 電影和語種的關系屬于一對一

首先打開 Film.php (數(shù)據(jù)庫表, Film 所代表的模型), 加入函數(shù)如下

// 函數(shù)名可以隨意取, 但為了方便辨識, 采用了副表的表名
public function language() {
    // 調用 hasOne 函數(shù), 首參是副表的模型名稱, 2參是副鍵名稱, 3參是主鍵名稱
        return $this->hasOne('Language', 'language_id', 'language_id');
}

接下來嘗試使用

$film = Film::find(1);

dd($film->language);

注意到了嗎? 調用函數(shù)的方式竟然是以變量的形式,這是為了與跟進一步的篩選明顯地區(qū)分開
先看返回結果

object(Language)[30]
  public 'language_id' => string '1' (length=1)
  public 'name' => string 'English' (length=7)
  public 'last_update' => string '2006-02-15 05:02:19' (length=19)

很多時候我們并不只是單純地連接副表查看結果, 打個比方, 我們想知道該電影是否中文, 如果是, 分享給朋友, 那應該怎么做呢?

$film = Film::find(1);

if($film->language->name=='Chinese')
    shareToFirends();

這段邏輯沒毛病, 但還有另一種實現(xiàn)方式

$film = Film::find(1);

$chinesFilm = $film->language()->where('name', 'Chinese')->first();

if($chinesFilm)
    shareToFirends();

以上例子說明了關聯(lián)函數(shù)是可以再操作的, 只要用函數(shù)的方式來調用

  1. 一對多

一個演員可以接演多部電影, 所以演員和電影的關系屬于一對多

打開 Actor.php (數(shù)據(jù)庫表, Actor 所代表的模型), 加入函數(shù)如下

// 由于返回的是多條數(shù)據(jù), 建議函數(shù)名是副表模型的復數(shù)
public function filmActors() {
    // 3個參數(shù)的作用參照 hasOne 函數(shù)
        return $this->hasMany('FilmActor', 'actor_id', 'actor_id');
}

用法同 hasOne 函數(shù)

$actor = Actor::find(1);

dd($actor->filmActors);

返回結果

array (size=19)
  0 =>
    object(FilmActor)[48]
      public 'actor_id' => string '1' (length=1)
      public 'film_id' => string '1' (length=1)
      public 'last_update' => string '2006-02-15 05:05:03' (length=19)
  1 =>
    object(FilmActor)[52]
      public 'actor_id' => string '1' (length=1)
      public 'film_id' => string '23' (length=2)
      public 'last_update' => string '2006-02-15 05:05:03' (length=19)
  2 =>
    object(FilmActor)[56]
      public 'actor_id' => string '1' (length=1)
      public 'film_id' => string '25' (length=2)
      public 'last_update' => string '2006-02-15 05:05:03' (length=19)
  3 =>
    object(FilmActor)[60]
      public 'actor_id' => string '1' (length=1)
      public 'film_id' => string '106' (length=3)
      public 'last_update' => string '2006-02-15 05:05:03' (length=19)
......
  1. 一對多間接關聯(lián)

上一個例子的返回結果并沒有帶出什么實質訊息, 這是一種常見的數(shù)據(jù)庫結構, 一對多的關系并不直接關聯(lián), 而是通過中間表來儲存

Actor -> FilmActor -> Film

打開 Actor.php, 加上函數(shù)如下

public function films() {
    // 參數(shù)介紹請參照函數(shù)的附帶解釋
        return $this->hasManyThrough('FilmActor', 'Film' , 'actor_id', 'film_id', 'actor_id', 'film_id');
}

調用方式

$actor = Actor::find(1);

dd($actor->films);

返回結果

array (size=19)
  0 =>
    object(Film)[49]
      public 'film_id' => string '1' (length=1)
      public 'title' => string 'ACADEMY DINOSAUR' (length=16)
      public 'description' => string 'A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies' (length=96)
      public 'release_year' => string '2006' (length=4)
      public 'language_id' => string '1' (length=1)
      public 'original_language_id' => null
      public 'rental_duration' => string '6' (length=1)
      public 'rental_rate' => string '0.99' (length=4)
      public 'length' => string '86' (length=2)
      public 'replacement_cost' => string '20.99' (length=5)
      public 'rating' => string 'PG' (length=2)
      public 'special_features' => string 'Deleted Scenes,Behind the Scenes' (length=32)
      public 'last_update' => string '2006-02-15 05:03:42' (length=19)
  1 =>
    object(Film)[53]
      public 'film_id' => string '23' (length=2)
      public 'title' => string 'ANACONDA CONFESSIONS' (length=20)
      public 'description' => string 'A Lacklusture Display of a Dentist And a Dentist who must Fight a Girl in Australia' (length=83)
      public 'release_year' => string '2006' (length=4)
      public 'language_id' => string '1' (length=1)
      public 'original_language_id' => null
      public 'rental_duration' => string '3' (length=1)
      public 'rental_rate' => string '0.99' (length=4)
      public 'length' => string '92' (length=2)
      public 'replacement_cost' => string '9.99' (length=4)
      public 'rating' => string 'R' (length=1)
      public 'special_features' => string 'Trailers,Deleted Scenes' (length=23)
      public 'last_update' => string '2006-02-15 05:03:42' (length=19)
......

以上就是本期的所有內容了, 實在無法評價自己的文筆, 如果看不懂可以在下方留言

完整代碼

源代碼放在coding.net里, 自己領

上一期 如何寫一個屬于自己的數(shù)據(jù)庫封裝(10) - 自動載入篇
下一期 如何寫一個屬于自己的數(shù)據(jù)庫封裝(12) - 分頁篇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子漓藕,更是在濱河造成了極大的恐慌,老刑警劉巖怎虫,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孝扛,居然都是意外死亡蝇更,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門宛逗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坎匿,“玉大人,你說我怎么就攤上這事雷激√媸撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵屎暇,是天一觀的道長承桥。 經常有香客問我,道長根悼,這世上最難降的妖魔是什么凶异? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮挤巡,結果婚禮上唠帝,老公的妹妹穿的比我還像新娘。我一直安慰自己玄柏,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布贴铜。 她就那樣靜靜地躺著粪摘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绍坝。 梳的紋絲不亂的頭發(fā)上徘意,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音轩褐,去河邊找鬼椎咧。 笑死,一個胖子當著我的面吹牛把介,可吹牛的內容都是我干的勤讽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼拗踢,長吁一口氣:“原來是場噩夢啊……” “哼脚牍!你這毒婦竟也來了?” 一聲冷哼從身側響起巢墅,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤诸狭,失蹤者是張志新(化名)和其女友劉穎券膀,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驯遇,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡芹彬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叉庐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舒帮。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖眨唬,靈堂內的尸體忽然破棺而出会前,到底是詐尸還是另有隱情,我是刑警寧澤匾竿,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布瓦宜,位于F島的核電站,受9級特大地震影響岭妖,放射性物質發(fā)生泄漏临庇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一昵慌、第九天 我趴在偏房一處隱蔽的房頂上張望假夺。 院中可真熱鬧,春花似錦斋攀、人聲如沸已卷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侧蘸。三九已至,卻和暖如春鹉梨,著一層夾襖步出監(jiān)牢的瞬間讳癌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工存皂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晌坤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓旦袋,卻偏偏與公主長得像骤菠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疤孕,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容