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