提高 Laravel Eloquent 查詢的5個小技巧

王子飛發表於2021-03-12

翻譯自:aschmelyun.com/blog/5-tips-for-sup...

在過去的五年左右的時間裡,我一直在與Laravel合作,在那段時間裡,我遇到了一些案例,在這些案例中,我需要一種獨特或非典型的方式來從應用程式中返回資料。使用Eloquent提取資料變得容易,但是仍然有一些用例需要我進行一些挖掘和理解,以弄清楚如何做自己想完成的事情。

我在下面列出了其中的五個,以及程式碼示例和為每個示例返回的偽資料。

準備好? 讓我們開始吧!

有條件地建立查詢

假設我們有一個 Property 模型,其中包含 價格列以及是否允許您養寵物。當使用者訪問時,我們希望過濾掉資料example.com/properties?rent=1200&pets=true

public function test(Request $request)
{
    if ($request->get('rent') && $request->get('pets')) {
        return Property::where('rent', <=, $request->get('rent'))->where('pets_allowed', true))->get();
    }

    if ($request->get('rent')) {
        return Property::where('rent', <=, $request->get('rent'))->get();
    }

    if ($request->get('pets')) {
        return Property::where('pets_allowed', true))->get();
    }

    return Property::all();
}

我們可以建立一個查詢,然後根據這些條件(而不是依賴它們)新增到查詢中。
使用Model::query(),然後我們可以根據存在的過濾器連結到 where 語句上。
最後呼叫get返回我們的資料:

public function test(Request $request)
{
    $properties = Property::query();

    if ($request->get('rent')) {
        $properties->where('rent', <=, $request->get('rent'));
    }

    if ($request->get('pets')) {
        $properties->where('pets_allowed', true));
    }

    return $properties->get();
}

這樣可以確保每個過濾器僅需要一個條件語句,並且可以將過濾器組合自動連結到此查詢。

返回最新關係

以我們之前的 Property 模型為例,假設有多個與 Tenant 模型相關聯的 租戶 模型。要拉入所有帶有其附加租戶的屬性,您可能會使用類似以下內容的方法:

public function test(Request $request)
{
    return Property::with('tenants')->get();
}

但是,如果您只想返回一位租戶,該怎麼辦?

public function tenants()
{
    return $this->hasMany(Tenant::class);
}

public function newestTenant()
{
    return $this->hasOne(Tenant::class)->orderBy('lease_expires_at', 'desc');
}

現在,如果我們回到以前的測試方法並將其修改為用 Property::with('newestTenant'),我們將只得到一個租戶。

按巢狀值過濾專案

使用我們之前的財產租戶模型以及關係,如果只想返回那些租戶沒有狗或貓的財產,該怎麼辦?您可能可以使用類似以下的內容:

public function test(Request $request)
{
    return Property::with(['tenants' => function($query) {
        $query->where('has_dogs', false)->where('has_cats', false);
    }])->get();
}

但我想做的是過濾掉這些屬性,然後只返回那些包含那些過濾後的關係的屬性。我們可以在物件上執行一個foreach迴圈並檢查該空的租戶陣列,或者可以使用Eloquent的whereHas()方法:

public  function test(Request $request) { 
    return Property::whereHas('tenants', function($query) { 
        $query->where('has_dogs', false)->where('has_cats', false); 
    })->with(['tenants' => function($query) { 
        $query->where('has_dogs', false)->where('has_cats', false);
    }])->get(); 
}

通過使用whereHas(),上面的方法返回與作為第一個引數輸入的列匹配的那些屬性。我們的第二個引數基於連結到查詢物件的方法過濾該列。

然後,我們通過將這些租戶附加到返回的屬性中來進行後續操作,並獲得結果。

生成和插入動態屬性

我們假設有兩個新模型:TechniciansRequests。技術人員與其他技術人員共享多個請求。如果我們希望有一種方法可以一眼就能輕鬆地看到我們的資料,那麼每個技術人員物件有多少個請求呢?我們可以將它們每個都作為延遲載入包含進來,然後獲取陣列的長度,或者我們可以建立一個動態屬性來計算並儲存該值。

首先,我們必須在Technician模型新增以下方法:

public function getRequestsCountAttribute()
{
    return $this->requests()->count();
}

在Laravel中,動態屬性的命名約定:

  • 使用camelCase
  • get開始
  • 包含您想要的下一個列名稱
  • 結束於 Attribute

因此,以上方法將在我們返回的技術人員上建立一個動態列,稱為requests_count,該列將包含附加至模型的已連線請求的數量。

輕鬆過濾日期

關於第五個也是最後一個技巧,讓我們回到租戶模型。正如我們前面提到的,每個人的租約到期時都有一列要儲存。好吧,如果我們只想返回那些在2021年7月到期的使用者,該怎麼辦?

我們也許可以做類似的事情:

public function test(Request $request)
{
    return Tenant::where('lease_expires_at', 'LIKE', '2021-07-%')->get();
}

那將完美地工作,並且只返回我們想要的租戶。但是我並不熱衷於LIKE在不需要的地方使用語句。它們可能會變得凌亂,Laravel為我們提供了兩種更好的方法:

public function test(Request $request)
{
    return Tenant::whereMonth('lease_expires_at', '07')->whereYear('lease_expires_at', '2021)->get();
}

使用whereMonthwhereYear,我們只能過濾那些租約在2021年7月到期的模型。如果我們想提供一些動態過濾功能,我們甚至可以將那些硬編碼的值替換為,$request->get('month')或者$request->get('year')則可以替換。

目前為止就這樣了!

這是五個簡單但功能強大的方法和組織技巧,可用於Laravel的Eloquent ORM來提高生產力。此外,這可能有助於您開始思考如何優化查詢並減少整體程式碼混亂。

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

相關文章