摘要:本文翻譯改編自的十八個最佳實踐這篇文章并不是什么由改編的原則模式等。只是為了讓你注意你在現實生活的項目中最常忽略的內容。單一職責原則正在幫助你避免重復。當然,這也包括了模板的范圍等。此外,也擁有很棒的內置工具,比如軟刪除事件范圍等。
</>復制代碼
本文翻譯改編自 Laravel 的十八個最佳實踐
這篇文章并不是什么由 Laravel 改編的 SOLID 原則、模式等。
只是為了讓你注意你在現實生活的 Laravel 項目中最常忽略的內容。
單一責任原則一個類和一個方法應該只有一個職責。
錯誤的做法:
</>復制代碼
public function getFullNameAttribute()
{
if (auth()->user() && auth()->user()->hasRole("client") && auth()->user()->isVerified()) {
return "Mr. " . $this->first_name . " " . $this->middle_name . " " $this->last_name;
} else {
return $this->first_name[0] . ". " . $this->last_name;
}
}
推薦的做法:
</>復制代碼
public function getFullNameAttribute()
{
return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}
public function isVerfiedClient()
{
return auth()->user() && auth()->user()->hasRole("client") && auth()->user()->isVerified();
}
public function getFullNameLong()
{
return "Mr. " . $this->first_name . " " . $this->middle_name . " " . $this->last_name;
}
public function getFullNameShort()
{
return $this->first_name[0] . ". " . $this->last_name;
}
強大的模型 & 簡單控制器
如果你使用查詢構造器或原始 SQL 來查詢,請將所有與數據庫相關的邏輯放入 Eloquent 模型或存儲庫類中。
壞:
</>復制代碼
public function index()
{
$clients = Client::verified()
->with(["orders" => function ($q) {
$q->where("created_at", ">", Carbon::today()->subWeek());
}])
->get();
return view("index", ["clients" => $clients]);
}
好:
</>復制代碼
public function index()
{
return view("index", ["clients" => $this->client->getWithNewOrders()]);
}
Class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(["orders" => function ($q) {
$q->where("created_at", ">", Carbon::today()->subWeek());
}])
->get();
}
}
驗證
將驗證從控制器移動到請求類。
很常見但不推薦的做法:
</>復制代碼
public function store(Request $request)
{
$request->validate([
"title" => "required|unique:posts|max:255",
"body" => "required",
"publish_at" => "nullable|date",
]);
....
}
最好是這樣:
</>復制代碼
public function store(PostRequest $request)
{
....
}
class PostRequest extends Request
{
public function rules()
{
return [
"title" => "required|unique:posts|max:255",
"body" => "required",
"publish_at" => "nullable|date",
];
}
}
業務邏輯應該在服務類中
一個控制器必須只有一個職責,因此應該將業務邏輯從控制器移到服務類。
壞:
</>復制代碼
public function store(Request $request)
{
if ($request->hasFile("image")) {
$request->file("image")->move(public_path("images") . "temp");
}
....
}
好:
</>復制代碼
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file("image"));
....
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path("images") . "temp");
}
}
}
不要重復你自己(DRY)
盡可能重用代碼。 SRP(單一職責原則)正在幫助你避免重復。當然,這也包括了 Blade 模板、Eloquent 的范圍等。
壞:
</>復制代碼
public function getActive()
{
return $this->where("verified", 1)->whereNotNull("deleted_at")->get();
}
public function getArticles()
{
return $this->whereHas("user", function ($q) {
$q->where("verified", 1)->whereNotNull("deleted_at");
})->get();
}
好:
</>復制代碼
public function scopeActive($q)
{
return $q->where("verified", 1)->whereNotNull("deleted_at");
}
public function getActive()
{
return $this->active()->get();
}
public function getArticles()
{
return $this->whereHas("user", function ($q) {
$q->active();
})->get();
}
最好傾向于使用 Eloquent 而不是 Query Builder 和原生的 SQL 查詢。要優先于數組的集合
Eloquent 可以編寫可讀和可維護的代碼。此外,Eloquent 也擁有很棒的內置工具,比如軟刪除、事件、范圍等。
比如你這樣寫:
</>復制代碼
SELECT *
FROM `articles`
WHERE EXISTS (SELECT *
FROM `users`
WHERE `articles`.`user_id` = `users`.`id`
AND EXISTS (SELECT *
FROM `profiles`
WHERE `profiles`.`user_id` = `users`.`id`)
AND `users`.`deleted_at` IS NULL)
AND `verified` = "1"
AND `active` = "1"
ORDER BY `created_at` DESC
還不如這樣寫:
</>復制代碼
Article::has("user.profile")->verified()->latest()->get();
批量賦值
比如你這樣寫:
</>復制代碼
$article = new Article;
$article->title = $request->title;
$article->content = $request->content;
$article->verified = $request->verified;
// Add category to article
$article->category_id = $category->id;
$article->save();
是不是還不如這樣寫:
不要在 Blade 模板中執行查詢并使用關聯加載(N + 1 問題)</>復制代碼
$category->article()->create($request->all());
不好的地方在于,這對于100 個用戶來說,等于執行 101 個 DB 查詢:
</>復制代碼
[@foreach](https://laravel-china.org/users/5651) (User::all() as $user)
{{ $user->profile->name }}
@endforeach
下面的做法,對于 100 個用戶來說,僅僅只執行 2 個 DB 查詢:
</>復制代碼
$users = User::with("profile")->get();
...
[[@foreach](https://laravel-china.org/users/5651)](https://laravel-china.org/users/5651) ($users as $user)
{{ $user->profile->name }}
@endforeach
與其花盡心思給你的代碼寫注釋,還不如對方法或變量寫一個描述性的名稱
壞:
</>復制代碼
if (count((array) $builder->getQuery()->joins) > 0)
好:
</>復制代碼
// 確定是否有任何連接。
if (count((array) $builder->getQuery()->joins) > 0)
最好:
</>復制代碼
if ($this->hasJoins())
不要把 JS 和 CSS 放在 Blade 模板中,也不要將任何 HTML 放在 PHP 類中
壞:
</>復制代碼
let article = `{{ json_encode($article) }}`;
好:
</>復制代碼
Or
最好的方法是使用在 Javascript 中這樣來傳輸數據:
</>復制代碼
let article = $("#article").val();
在代碼中使用配置和語言文件、常量,而不是寫死它
壞:
</>復制代碼
public function isNormal()
{
return $article->type === "normal";
}
return back()->with("message", "Your article has been added!");
好:
</>復制代碼
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with("message", __("app.article_added"));
使用社區接受的標準的 Laravel 工具
最好使用內置的 Laravel 功能和社區軟件包,而不是其他第三方軟件包和工具。因為將來與你的應用程序一起工作的開發人員都需要學習新的工具。另外,使用第三方軟件包或工具的話,如果遇到困難,從 Laravel 社區獲得幫助的機會會大大降低。不要讓你的客戶為此付出代價!
任務 | 標準工具 | 第三方工具 |
---|---|---|
授權 | Policies | Entrust, Sentinel and other packages |
前端編譯 | Laravel Mix | Grunt, Gulp, 3rd party packages |
開發環境 | Homestead | Docker |
部署 | Laravel Forge | Deployer and other solutions |
單元測試 | PHPUnit, Mockery | Phpspec |
瀏覽器測試 | Laravel Dusk | Codeception |
數據庫操作 | Eloquent | SQL, Doctrine |
模板 | Blade | Twig |
數據操作 | Laravel collections | Arrays |
表單驗證 | Request classes | 3rd party packages, validation in controller |
認證 | Built-in | 3rd party packages, your own solution |
API 認證 | Laravel Passport | 3rd party JWT and OAuth packages |
創建 API | Built-in | Dingo API and similar packages |
數據庫結構操作 | Migrations | Working with DB structure directly |
局部化 | Built-in | 3rd party packages |
實時用戶接口 | Laravel Echo, Pusher | 3rd party packages and working with WebSockets directly |
Generating testing data | Seeder classes, Model Factories, Faker | Creating testing data manually |
生成測試數據 | Laravel Task Scheduler | Scripts and 3rd party packages |
數據庫 | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB |
遵循 PSR 標準。 另外,請遵循 Laravel 社區接受的命名約定:
類型 | 規則 | 正確示例 | 錯誤示例 |
---|---|---|---|
Controller | 單數 | ArticleController | |
Route | 復數 | articles/1 | |
Named route | 帶點符號的蛇形命名 | users.show_active | |
Model | 單數 | User | |
hasOne or belongsTo relationship | 單數 | articleComment | |
All other relationships | 復數 | articleComments | |
Table | 復數 | article_comments | |
Pivot table | 按字母順序排列的單數模型名稱 | article_user | |
Table column | 帶著模型名稱的蛇形命名 | meta_title | |
Foreign key | 帶_id后綴的單數型號名稱 | article_id | |
Primary key | - | id | |
Migration | - | 2017_01_01_000000_create_articles_table | |
Method | 小駝峰命名 | getAll | |
Method in resource controller | 具體看表格 | store | |
Method in test class | 小駝峰命名 | testGuestCannotSeeArticle | |
Variable | 小駝峰命名 | $articlesWithAuthor | |
Collection | 具描述性的復數形式 | $activeUsers = User::active()->get() | |
Object | 具描述性的單數形式 | $activeUser = User::active()->first() | |
Config and language files index | 蛇形命名 | articles_enabled | |
View | 蛇形命名 | show_filtered.blade.php | |
Config | 蛇形命名 | google_calendar.php | |
Contract (interface) | 形容詞或名詞 | Authenticatable | |
Trait | 形容詞 | Notifiable |
壞:
</>復制代碼
$request->session()->get("cart");
$request->input("name");
好:
</>復制代碼
session("cart");
$request->name;
更多示例:
通用語法 | 更短、更可讀的語法 |
---|---|
Session::get("cart") | session("cart") |
$request->session()->get("cart") | session("cart") |
Session::put("cart", $data) | session(["cart" => $data]) |
$request->input("name"), Request::get("name") | $request->name, request("name") |
return Redirect::back() | return back() |
is_null($object->relation) ? $object->relation->id : null } | optional($object->relation)->id |
return view("index")->with("title", $title)->with("client", $client) | return view("index", compact("title", "client")) |
$request->has("value") ? $request->value : "default"; | $request->get("value", "default") |
Carbon::now(), Carbon::today() | now(), today() |
App::make("Class") | app("Class") |
->where("column", "=", 1) | ->where("column", 1) |
->orderBy("created_at", "desc") | ->latest() |
->orderBy("age", "desc") | ->latest("age") |
->orderBy("created_at", "asc") | ->oldest() |
->select("id", "name")->get() | ->get(["id", "name"]) |
->first()->name | ->value("name") |
新的 Class 語法創建類時,不僅使得類與類之間緊密耦合,還加重了測試的復雜度。推薦改用 IoC 容器或 facades。
壞:
</>復制代碼
$user = new User;
$user->create($request->all());
好:
</>復制代碼
public function __construct(User $user)
{
$this->user = $user;
}
....
$this->user->create($request->all());
不要直接從 .env 文件獲取數據
將數據傳遞給配置文件,然后使用輔助函數?config()?在應用程序中使用數據。
壞:
</>復制代碼
$apiKey = env("API_KEY");
好:
</>復制代碼
// config/api.php
"key" => env("API_KEY"),
// Use the data
$apiKey = config("api.key");
以標準格式存儲日期,必要時就使用訪問器和修改器來修改日期格式
壞:
</>復制代碼
{{ Carbon::createFromFormat("Y-d-m H-i", $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat("Y-d-m H-i", $object->ordered_at)->format("m-d") }}
好:
</>復制代碼
// Model
protected $dates = ["ordered_at", "created_at", "updated_at"]
public function getMonthDayAttribute($date)
{
return $date->format("m-d");
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->monthDay }}
其他良好做法
千萬不要在路由文件中放置任何邏輯。
在 Blade 模板中最小化 vanilla PHP 的使用。
</>復制代碼
更多現代化 PHP 知識,請前往 Laravel / PHP 知識社區
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28746.html
摘要:初步嘗試既然最常見的注冊命令的方式是修改類中的,那么一般正常人都會從這邊開始下手。又要自己取出實例,又要自己調用方法,調用方法之前還有自己先把實例化這么繁瑣,肯定不是運行時添加命令的最佳實踐,所以我決定繼續尋找更優解。 本文首發于我的博客,原文鏈接:https://blessing.studio/best-... 雖然 Laravel 官方文檔提供的添加 Artisan Command...
摘要:事件驅動編程是圖形用戶界面和其他應用程序例如應用程序中使用的主要范例,用于執行某些操作來響應用戶輸入。我們來看一下事件驅動編程帶來的收益。現在讓我們看看采用事件驅動編程方法如何實現上述相同的功能。 在這篇文章中我們將了解到什么是事件驅動編程以及在Laravel中如何開始構建一個事件驅動應用,同時我們還將看到如何通過事件驅動編程來對應用程序的邏輯進行解耦。 在開始之前,先說明一下這篇文章...
摘要:是指可能導致程序終止的非常嚴重的時間。具有最高的級別,旨在關閉中的日志功能。因此為每一個消息選擇一個合適的日志級別是非常重要的。日志的個小建議將日志訪日代碼塊它能顯著的減少因為字符串拼接而帶來的性能的影響。 前言 首先,這篇文章沒有進行任何的日志功能的詳細介紹,而是對日志提出了幾種最佳實踐。適合對日志記錄有所了解的同學閱讀。下面是正文: JAVA日志管理既是一門科學,又是一門藝術。科學...
摘要:當查詢數據時,本地范圍允許我們創建自己的查詢構造器鏈式方法。這樣便會知道這是一個本地范圍并且可以在查詢構造器中使用。某些查詢構造器不可用或者說可用但是方法名不同,關于這些請查閱所有集合的方法。 showImg(https://segmentfault.com/img/remote/1460000017877956?w=800&h=267); Laravel 因可編寫出干凈,可用可調試的...
閱讀 2024·2021-10-09 09:41
閱讀 1601·2021-09-28 09:36
閱讀 1104·2021-09-26 09:55
閱讀 1294·2021-09-10 11:17
閱讀 1146·2021-09-02 09:56
閱讀 2763·2019-08-30 12:58
閱讀 2936·2019-08-29 13:03
閱讀 1855·2019-08-26 13:40