摘要:當(dāng)查詢數(shù)據(jù)時,本地范圍允許我們創(chuàng)建自己的查詢構(gòu)造器鏈?zhǔn)椒椒?。這樣便會知道這是一個本地范圍并且可以在查詢構(gòu)造器中使用。某些查詢構(gòu)造器不可用或者說可用但是方法名不同,關(guān)于這些請查閱所有集合的方法。
Laravel 因可編寫出干凈,可用可調(diào)試的代碼而為廣大的 PHP 開發(fā)者所熟知。它同樣也支持許許多多的功能,有時卻未能在文檔中體現(xiàn),或者由于某種原因它們出現(xiàn)過又被移除了。
我已經(jīng)在生產(chǎn)環(huán)境中使用 Laravel 2 年了,從中我學(xué)到如何把代碼變得更好,從我首次使用它以來我都充分發(fā)掘它的優(yōu)勢。接下來我將向你展示一些可能對你在用 Laravel 寫代碼時很有幫助的奧義之招。
*
查詢數(shù)據(jù)時使用本地范圍Laravel 有一種非常棒的方式來使用 查詢構(gòu)造器 編寫查詢。就像這樣:
$orders = Order::where("status", "delivered")->where("paid", true)->get();
很不錯。這讓我專注于編寫更友好的代碼而不是 SQL 語句。但如果用 本地范圍 ,我們可以讓這行代碼變得更好些。
當(dāng)查詢數(shù)據(jù)時, 本地范圍 允許我們創(chuàng)建自己的 查詢構(gòu)造器 鏈?zhǔn)椒椒āEe個例子,取代 ->where() ,我們可以用更簡潔的?->delivered()?和?->paid()?。
首先在 Order?模型,我們加入一些方法:
class Order extends Model { ... public function scopeDelivered($query) { return $query->where("status", "delivered"); } public function scopePaid($query) { return $query->where("paid", true); } }
當(dāng)聲明本地范圍時,你應(yīng)該使用 scope[Something] 來命名。這樣 Laravel 便會知道這是一個本地范圍并且可以在查詢構(gòu)造器中使用。請確保你在方法中傳入了第一個參數(shù) $query,也就是由 Laravel 自動注入的查詢構(gòu)造器實例。
$orders = Order::delivered()->paid()->get();
對于可接受額外參數(shù)的查詢,你可以使用動態(tài)范圍。每個范圍都允許你傳入額外的參數(shù)。
class Order extends Model { ... public function scopeStatus($query, string $status) { return $query->where("status", $status); } } $orders = Order::status("delivered")->paid()->get();
在本文的后面,你會知道為什么數(shù)據(jù)庫字段應(yīng)該使用 蛇形命名,但這里有第一個原因:Laravel 默認(rèn)用 where[Something] 來替換 scope[Something] 。所以作為 scopeStatus 范圍的代替,你可以這樣做:
Order::whereStatus("delivered")->paid()->get();
對于 where[Something] ,Laravel 會搜索 蛇形命名 版本的數(shù)據(jù)庫字段。如果你的數(shù)據(jù)庫中有個 status 字段,你可以用上面那個例子。如果有個 shipping_status 字段,你可以用:
Order::whereShippingStatus("delivered")->paid()->get();
由你決定!
必要的時候使用請求類Laravel 提供了一種優(yōu)秀的方式來驗證表單提交的數(shù)據(jù)。如果你需要它,不管是 POST 還是 GET 請求,它都可以驗證。
在控制器中,你可以這樣做:
public function store(Request $request) { $validatedData = $request->validate([ "title" => "required|unique:posts|max:255", "body" => "required", ]); // 如果這篇博客的內(nèi)容無效…… }
但是當(dāng)控制器中已經(jīng)有很多代碼時,再把驗證表單數(shù)據(jù)的代碼加進去就會顯得很凌亂。你想盡可能地減少控制器的代碼 —— 至少這是我在控制器中寫很多邏輯時想到的第一件事。
Laravel 提供了一種很萌的方式來驗證表單請求,那就是創(chuàng)建并使用專門的 請求類 而不是用原始的 Request 。你只需要創(chuàng)建你的請求類:
php artisan make:request StoreBlogPost
在 app/Http/Requests/ 目錄中可以找到你剛創(chuàng)建的請求類:
class StoreBlogPostRequest extends FormRequest { public function authorize() { return $this->user()->can("create.posts"); } public function rules() { return [ "title" => "required|unique:posts|max:255", "body" => "required", ]; } }
現(xiàn)在,你應(yīng)該用新創(chuàng)建的 AppHttpRequestsStoreBlogPostRequest 來代替原先的 IlluminateHttpRequest 類:
use AppHttpRequestsStoreBlogPostRequest; public function store(StoreBlogPostRequest $request) { // 如果這篇博客的內(nèi)容無效…… }
請求類中的 authorize() 方法應(yīng)返回一個布爾值。如果返回了 false,它會拋出一個 403 異常,請確保你在 ?app/Exceptions/Handler.php 的 render() 方法中捕獲了這個異常:
public function render($request, Exception $exception) { if ($exception instanceof IlluminateAuthAccessAuthorizationException) { // } return parent::render($request, $exception); }
請求類中還有一個?messages() 方法,當(dāng)驗證失敗時,它會返回一個包含了錯誤信息的數(shù)組:
class StoreBlogPostRequest extends FormRequest { public function authorize() { return $this->user()->can("create.posts"); } public function rules() { return [ "title" => "required|unique:posts|max:255", "body" => "required", ]; } public function messages() { return [ "title.required" => "The title is required.", "title.unique" => "The post title already exists.", ... ]; } }
@if ($errors->any()) @foreach ($errors->all() as $error) {{ $error }} @endforeach @endif
如果你想得到某個字段的驗證信息,你可以這樣做(當(dāng)這個字段驗證通過時 $errors->has() 會返回一個 false):
@if ($errors->has("title")) @endif魔術(shù)范圍
構(gòu)建查詢時,可以使用已有的魔術(shù)范圍:
根據(jù) created_at?倒序查詢:
User::latest()->get();
根據(jù)任意字段倒序查詢:
User::latest("last_login_at")->get();
隨機查詢(即 SQL 語句中的 ORDER BY RAND())
User::inRandomOrder()->get();使用關(guān)聯(lián)關(guān)系代替冗長的查詢(或者寫得不好的查詢)
你是否曾經(jīng)為了獲取更多的信息而在查詢語句中使用大量的 join 操作?即使在使用查詢構(gòu)造器的情況下,編寫這樣的 SQL 語句也是困難的,但是數(shù)據(jù)模型已經(jīng)使用 關(guān)聯(lián)關(guān)系 來實現(xiàn)同樣的功能。由于文檔提供了太多的信息,因此剛開始時你可能對關(guān)聯(lián)關(guān)系并不熟悉,但是這些內(nèi)容可以幫助你更好的理解事物的運行原理,同時讓你的程序運行得更加順暢。
通過 這里 查詢關(guān)聯(lián)關(guān)系的文檔。
為耗時的任務(wù)使用任務(wù)系統(tǒng)Laravel 的任務(wù) 是后臺運行程序必用的功能強大的工具。
你要發(fā)送電子郵件? 任務(wù)系統(tǒng)。
你要廣播一個消息? 任務(wù)系統(tǒng)。
你要處理一張圖片? 任務(wù)系統(tǒng)。
任務(wù)系統(tǒng)能夠幫助你實現(xiàn),在執(zhí)行上述這些任務(wù)時,減少你的用戶的應(yīng)用加載時間。這些任務(wù)可以被放進命名的隊列,它們能夠被安排優(yōu)先級,Laravel 幾乎在所有可能的地方都實現(xiàn)了隊列:無論在后臺執(zhí)行一些 PHP 任務(wù),或者發(fā)送消息,或者廣播事件,隊列都在這些場景中出現(xiàn)。
你可以在 這里 查詢隊列的文檔。
在使用隊列時,我喜歡使用 Laravel Horizon?,因為它很容易安裝,它能夠通過 Supervisor 工具或者配置文件實現(xiàn)后臺運行,同時我能夠告訴 Horizon 我希望每個隊列產(chǎn)生多少個進程。
遵守數(shù)據(jù)庫標(biāo)準(zhǔn) & 訪問器Laravel 從一開始就教給你變量和方法應(yīng)使用像?$camelCase camelCase()?這樣的小駝峰命名而數(shù)據(jù)庫字段應(yīng)使用像 snake_case 這樣的蛇形命名。為什么呢?因為這有助于我們構(gòu)造更好的 訪問器。
訪問器是可以直接在模型中構(gòu)造的自定義字段。如果我們的數(shù)據(jù)庫包含了?first_name、last_name、age 這幾個字段,我們可以增加一個叫做 name 的自定義字段來把 first_name 和 last_name 拼接起來。別擔(dān)心,這個 name 不會被寫入到數(shù)據(jù)庫。它只是某個模型的自定義屬性。所有的訪問器,和 范圍 一樣,都有自定義命名語法:getSomethingAttribute:
class User extends Model { ... public function getNameAttribute(): string { return $this->first_name." ".$this->last_name; } }
當(dāng)使用 $user->name,訪問器會返回拼接好的字符串。
*
默認(rèn)情況下,用 dd($user) 是看不到 name 屬性的,但是通過?$appends?變量我們可以使它一直可用:
class User extends Model { protected $appends = [ "name", ]; ... public function getNameAttribute(): string { return $this->first_name." ".$this->last_name; } }
現(xiàn)在每次 dd($user),我們都可以看到 name 了。(不過仍然,這個屬性不是從數(shù)據(jù)庫取得的,而是每次使用時將 first_name 和 last_name 拼接得到的)。
要注意下,如果你數(shù)據(jù)庫里已經(jīng)有 name 這個字段了,那情況就會有點不一樣:$appends 數(shù)組里的 name 元素就不需要了,然后訪問器需要傳入一個參數(shù),這個參數(shù)就是數(shù)據(jù)庫中的 name (也就是說我們用不著再使用 $this 了)。
舉個例子,我們也許想用 ucfirst() 來使名字的首字母轉(zhuǎn)為大寫:
class User extends Model { protected $appends = [ // ]; ... public function getFirstNameAttribute($firstName): string { return ucfirst($firstName); } public function getLastNameAttribute($lastName): string { return ucfirst($lastName); } }
現(xiàn)在當(dāng)我們用 $user->first_name,它會返回一個首字母大寫的字符串。
由于這個特性,數(shù)據(jù)庫字段最好是用 snake_case 這種蛇形命名。
不要在配置文件中存儲模型相關(guān)的靜態(tài)數(shù)據(jù)我喜歡把與模型相關(guān)的靜態(tài)數(shù)據(jù)存放在模型文件中。讓我們一起來看一下。
不要像下面這樣:
BettingOdds.php
class BettingOdds extends Model { ... }
config/bettingOdds.php
return [ "sports" => [ "soccer" => "sport:1", "tennis" => "sport:2", "basketball" => "sport:3", ... ], ];
使用下面的方式訪問:
config("bettingOdds.sports.soccer");
我更喜歡這樣做:
BettingOdds.php
class BettingOdds extends Model { protected static $sports = [ "soccer" => "sport:1", "tennis" => "sport:2", "basketball" => "sport:3", ... ]; }
然后訪問它們:
BettingOdds::$sports["soccer"];
為什么這樣?因為這樣有益于后續(xù)操作:
class BettingOdds extends Model { protected static $sports = [ "soccer" => "sport:1", "tennis" => "sport:2", "basketball" => "sport:3", ... ]; public function scopeSport($query, string $sport) { if (! isset(self::$sports[$sport])) { return $query; } return $query->where("sport_id", self::$sports[$sport]); } }
現(xiàn)在我們可以使用范圍查詢:
BettingOdds::sport("soccer")->get();使用集合替代原始的數(shù)組處理
在過去,我們通常以一種原始的方式使用數(shù)組:
$fruits = ["apple", "pear", "banana", "strawberry"]; foreach ($fruits as $fruit) { echo "I have ". $fruit; }
現(xiàn)在,我們可以使用一種高級的方法(譯者注:集合的方式)處理數(shù)組中的數(shù)據(jù)。我們可以過濾、轉(zhuǎn)換、遍歷和修改數(shù)組中數(shù)據(jù):
$fruits = collect($fruits); $fruits = $fruits->reject(function ($fruit) { return $fruit === "apple"; })->toArray(); ["pear", "banana", "strawberry"]
想要了解細(xì)節(jié), 請查看?集合的文檔.
當(dāng)使用 查詢構(gòu)造器時,->get()?方法返回一個?Collection?實例。但要注意別搞混了 Collection?和?Query builder:
從 Query Builder 中,我們無法獲取任何數(shù)據(jù).。但我們有大量的查詢相關(guān)的方法可以使用:orderBy(),?where(),等等。
最終調(diào)用?->get() 方法之后,數(shù)據(jù)被獲取到,內(nèi)存空間被消耗。它返回一個?Collection?實例。某些查詢構(gòu)造器不可用或者說可用但是方法名不同,關(guān)于這些請查閱?所有集合的方法。
如果你能在?Query Builder?層次過濾數(shù)據(jù),就去做吧!不要依賴于等到結(jié)果 Collection 實例返回時再過濾---你將會消耗更多的內(nèi)存空間。?使用 Limit 限制結(jié)果條數(shù),在 DB 層使用索引來加快查詢。
善用擴展包、不要重復(fù)造輪子如下是一些我在用的擴展包:
Laravel Blade Directives
Laravel CORS(跨域請求時,將你的路由限制為指定域名訪問)
Laravel Tag Helper(在 Blade 內(nèi)更方便地使用 HTML 標(biāo)簽)
Laravel Sluggable(在 Eloquent 模型內(nèi)生成 Slug 時十分實用)
Laravel Responder(更容易地構(gòu)建 JSON API)
Image Intervention(處理圖片)
Horizon(使用少量配置即可管理隊列)
Socialite(使用少量配置即可集成第三方社交媒體登錄)
Passport(集成 OAuth 路由)
Spatie"s ActivityLog(追蹤模型的修改活動)
Spatie"s Backup(備份文件和數(shù)據(jù)庫)
Spatie"s Blade-X(定義你自己的 HTML 標(biāo)簽;可與 Laravel Tag Helper 結(jié)合)
Spatie"s Media Library(快速將模型與文件關(guān)聯(lián))
Spatie"s Response Cache(緩存控制器的完整響應(yīng)內(nèi)容)
Spatie"s Collection Macros(給集合添加更多宏)
以下是我(原文作者)編寫的一些擴展包:
Befriended(類似社交媒體的點贊、收聽、屏蔽操作)
Schedule(創(chuàng)建日程表并檢查某個時間點是否可用)
Rating(為模型增加評分功能)
Guardian(易于使用的權(quán)限系統(tǒng))
太難理解?聯(lián)系我吧!如果你有更多關(guān)于 Laravel 的問題,如果你需要運維方面的幫助,或者只是想說聲 謝謝,你可以在 Twitter @rennokki 上找到我!
轉(zhuǎn)自 PHP / Laravel 開發(fā)者社區(qū) https://laravel-china.org/top...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/29949.html
摘要:使用即時編譯器和都能輕輕松松的讓你的應(yīng)用程序在不用做任何修改的情況下,直接提高或者更高的性能,之前做個一個實驗,具體請見使用提升程序性能。 本文經(jīng)授權(quán)轉(zhuǎn)自 PHPHub 社區(qū) 說明 性能一直是 Laravel 框架為人詬病的一個點,所以調(diào)優(yōu) Laravel 程序算是一個必學(xué)的技能。 接下來分享一些開發(fā)的最佳實踐,還有調(diào)優(yōu)技巧,大家有別的建議也歡迎留言討論。 這里是簡單的列表: 配置信...
摘要:關(guān)于,它使用起來簡單且舒適適用于編寫產(chǎn)品代碼,并能極大的推動開發(fā)過程。中我最喜歡的一點是它是使用當(dāng)下編程中的最佳實踐所構(gòu)建的。的工作原理是這樣的,對于一個命名為的表,希望該表的模型被命名為。盡量為每一個請求創(chuàng)建。 showImg(https://segmentfault.com/img/remote/1460000018303541?w=808&h=449); 將任何 PHP 框架稱為...
摘要:關(guān)于,它使用起來簡單且舒適適用于編寫產(chǎn)品代碼,并能極大的推動開發(fā)過程。這里有一些在開發(fā)中值得記住的簡單建議最大限度的使用你的文件不要破壞框架核心,不要編輯文件夾中的文件,你可以選擇繼承相關(guān)函數(shù)來實現(xiàn)。 showImg(https://segmentfault.com/img/remote/1460000018416776?w=808&h=449); 將任何 PHP 框架稱為最好的框架都...
摘要:最佳實踐良好的編碼規(guī)范單元測試持續(xù)集成文檔,從一開始就形成良好的編碼習(xí)慣。真實的電商業(yè)務(wù)所有的業(yè)務(wù)需求來自真實的客戶,并且線上良好運營中。 重要通知: Laravel + 小程序的開源電商版本源碼已經(jīng)在 github 上拉,歡迎提交 issue 和 star :) 開源電商 Server 端: Laravel API源碼 開源電商 client 端:小程序源碼 iBrand 簡介...
摘要:大刀闊斧的改造在學(xué)習(xí)了兩遍之后,基于教程開發(fā)的校園二手書交易平臺熊能本周閱讀清單紙牌屋弗蘭克知道的太晚了實現(xiàn)微信紅包拆分算法聊聊最近求職發(fā)生的故事無銘更多現(xiàn)代化知識,請前往知識社區(qū) showImg(https://segmentfault.com/img/bV8ctF?w=1650&h=1100); 最新資訊 Laravel 5.6 中文文檔翻譯完成,譯者 60 人,耗時 10 天...
閱讀 3020·2021-11-12 10:36
閱讀 4726·2021-09-22 10:57
閱讀 1558·2021-09-22 10:53
閱讀 2636·2019-08-30 15:55
閱讀 3492·2019-08-29 17:00
閱讀 3352·2019-08-29 16:36
閱讀 2463·2019-08-29 13:46
閱讀 1348·2019-08-26 11:45