Laravel 的 Eloquent模型 中的屬性訪問控制意義及實踐

咱們在定義一個本身的 Laravel 模型時都須要繼承 Illuminate\Database\Eloquent\Model 這個類,在這個類中定義了不少模型相關的操做和行爲。今天咱們來重點說說 Model 中包含的屬性。數據庫

在框架定義屬性中訪問權限通常有 protectedpublic 兩種,這兩種屬性是在咱們繼承基礎模型後能夠重寫的,那爲何不統一都是protected,是由於有一些屬性咱們須要去動態改變。框架

protected 的屬性咱們通常只重寫一次或者使用基類提供的默認值,例如:學習

protected $table
protected $primaryKey = 'id';
protected $keyType = 'int';複製代碼

以上這些都是隻須要在繼承基類的時候重寫就能夠了,分別表示模型的對應的表名、主鍵字段名、主鍵類型。spa

在軟件的生命週期內這些屬性都不須要再出改變。code

而有幾個特殊的屬性使用的 public 權限:繼承

public $incrementing = true;
public $exists = false;
public $wasRecentlyCreated = false;
public static $snakeAttributes = true;
public static $manyMethods = [
        'belongsToMany', 'morphToMany', 'morphedByMany',
        'guessBelongsToManyRelation', 'findFirstMethodThatIsntRelation',
    ];
public $timestamps = true;複製代碼

這些屬性有些在 Illuminate\Database\Eloquent\Model 有些在 Model 使用的 trait 中。生命週期

如今咱們就拿 $exists$timestamps 這兩個來舉例說明爲何框架會將他們的訪問屬性定義爲 public資源

$exists

這個屬性用來指示模型中數據是否存在,典型的判斷在 model 的 save() 方法中,若是 $exists = true 那麼 save() 執行的就是數據庫的 update 操做,若是是 false 執行的就是 instert 操做。rem

好比你有一個這樣的場景,這個模型在作正常的存儲的時候都是執行正常的 save 邏輯,而在特殊的時候須要所有操做都是 inster 操做就能夠在調用 save 前將此屬性手動賦值爲 true。get

這樣的場景有典型應用就是用戶。

public function register(Request $rquest) {

    $model = new User();

    $model->exists = false;

    $model->create($request->only('email', 'name', 'password'))

    $model->save()

}

public function updateName(Request $rquest) {

    $model = User::find($id, $request->get('id'));

    $model->exists = true;

    $model->name = $request->get('name')

    $model->save()

}複製代碼

以上是一個僞代碼的用戶註冊和用戶更新字段方法,咱們手動去將$exists屬性修改成咱們操做想要其達到效果以保證其每次執行都是咱們想要的效果而非產生咱們不想要的反作用。

固然這個例子可能不是一個最佳實踐,由於這些判斷框架內部都幫咱們坐在,這個屬性最大做用仍是用於判斷,好比你調用了一些模型操做,想要查看一看一下這個屬性的bool值,以幫助你作下一步的判斷,以執行不一樣的邏輯時更有做用。

$timestamps

這個屬性是我將要着重說的屬性,由於我認爲它在個人代碼中目前找到了最佳實踐。

我如今有一個表,是文章表,我在文章表裏冗餘了須要文章的屬性,好比閱讀數,關注數,評論數,收藏數,就是爲了減小獲取這篇文章的時候那些關聯查詢,以使得文章的首次加載速度更快。對我來講此時獲取一個關注的數去查詢一次文章關注表是不划算的。

可是我在獲取文章的是又要將閱讀數自增,以反映有人點開並閱讀了此文章一次。可是鑑於Laravel默認會自動管理個人文章模型 created_atupdated_at 這個兩個字段,我每次更改閱讀數,模型同時會更新記錄的 updated_at 到最新時間,這並非我想要的結果。

因而我將 $timestamps 在模型定義爲 false , 這樣個人時間就不會被框架自動管理。

可是這樣作又產生一個問題,雖然我不想我在更改閱讀數,關注數這些冗餘數據是讓框架自動管理個人記錄時間,可是我卻想在建立和文章編輯提交時更新時間。

固然方法有,我能夠手動傳遞當前時間給模型,也是能夠實現的。可是畢竟這樣不夠優雅,且原本框架提供的功能我卻要本身再去實現它,讓我以爲這是一種資源浪費,並且手動維護這些時間是繁瑣易出錯的。

當我看到這個訪問控制的 public 的時候,我以爲我能夠同時實現個人這兩個需求,並且不須要本身手動傳遞時間。

/** * 查看文章 */
public function showArticle($id) {
    $article = Article::find($id);

    $article->timestamps = false; // 模型已經定義,可省略

    $article->increment('views');

    $article->save();

    return $article;
}

/** * 建立文章 */
public function createArticle(Request $request) {
    $article = Article::crete($request->all());

    $article->timestamps = true;

    $article->save();

    return $article;
}

/** * 更新文章 */
public function updateArticle($id, Request $request) {
    $article = Article::find(id);

    $article->timestamps = true;

    $article->update($request->all());

    return $article;
}複製代碼

這樣我就不用手動傳遞時間給模型了,模型會用自身的功能幫我維護記錄的時間。

總結

這些 public 的屬性就是方便外部能夠訪問它們或者能夠根據本身場景來動態的改變它們,以符合你的指望,這些屬性我並無徹底研究清楚他們的最佳實踐,這篇文章算是拋磚迎玉,但願你們也能爲我提供大家的最佳實踐以供咱們互相學習。

相關文章
相關標籤/搜索