Larevel 最佳實踐(部分)

這篇文章并不是什么由 Laravel 改編的 SOLID 原則、模式等嗤谚。
只是為了讓你注意你在現(xiàn)實生活的 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 來查詢毅整,請將所有與數(shù)據(jù)庫相關的邏輯放入 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',
        ];
    }
}

業(yè)務邏輯應該在服務類中

一個控制器必須只有一個職責翻具,因此應該將業(yè)務邏輯從控制器移到服務類。
壞:

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();

是不是還不如這樣寫:

$category->article()->create($request->all());

不要在 Blade 模板中執(zhí)行查詢并使用關聯(lián)加載(N + 1 問題)

不好的地方在于坎缭,這對于100 個用戶來說竟痰,等于執(zhí)行 101 個 DB 查詢:

@foreach(User::all() as $user)
    {{ $user->profile->name }}
@endforeach

下面的做法,對于 100 個用戶來說掏呼,僅僅只執(zhí)行 2 個 DB 查詢:

$users = User::with('profile')->get();

...
@foreach($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) }}`;

好:

<input id="article" type="hidden" value="{{ json_encode($article) }}">

Or

<button class="js-fav-article" data-article="{{ json_encode($article) }}">{{ $article->name }}<button>

最好的方法是使用在 Javascript 中這樣來傳輸數(shù)據(jù):

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命名約定

盡可能使用更短、更易讀的語法

壞:

$request->session()->get('cart');
$request->input('name');

好:

session('cart');
$request->name;

使用 IoC 容器或 facades 代替 new Class

新的 Class 語法創(chuàng)建類時祥得,不僅使得類與類之間緊密耦合兔沃,還加重了測試的復雜度。推薦改用 IoC 容器或 facades级及。
壞:

$user = new User;
$user->create($request->all());

好:

public function __construct(User $user)
{
    $this->user = $user;
}

....

$this->user->create($request->all());

不要直接從 .env 文件獲取數(shù)據(jù)

將數(shù)據(jù)傳遞給配置文件乒疏,然后使用輔助函數(shù) config() 在應用程序中使用數(shù)據(jù)。
壞:

$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 }}

盡量不適用資源路由

為每個接口指定單獨的 view怕吴,盡量不使用 include

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市县踢,隨后出現(xiàn)的幾起案子转绷,更是在濱河造成了極大的恐慌,老刑警劉巖硼啤,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件议经,死亡現(xiàn)場離奇詭異,居然都是意外死亡谴返,警方通過查閱死者的電腦和手機煞肾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亏镰,“玉大人扯旷,你說我怎么就攤上這事∷髯ィ” “怎么了钧忽?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逼肯。 經(jīng)常有香客問我耸黑,道長,這世上最難降的妖魔是什么篮幢? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任大刊,我火速辦了婚禮,結果婚禮上三椿,老公的妹妹穿的比我還像新娘缺菌。我一直安慰自己,他們只是感情好搜锰,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布伴郁。 她就那樣靜靜地躺著,像睡著了一般蛋叼。 火紅的嫁衣襯著肌膚如雪焊傅。 梳的紋絲不亂的頭發(fā)上剂陡,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天,我揣著相機與錄音狐胎,去河邊找鬼鸭栖。 笑死,一個胖子當著我的面吹牛握巢,可吹牛的內容都是我干的晕鹊。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼镜粤,長吁一口氣:“原來是場噩夢啊……” “哼捏题!你這毒婦竟也來了玻褪?” 一聲冷哼從身側響起肉渴,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎带射,沒想到半個月后同规,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡窟社,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年券勺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灿里。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡关炼,死狀恐怖,靈堂內的尸體忽然破棺而出匣吊,到底是詐尸還是另有隱情儒拂,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布色鸳,位于F島的核電站社痛,受9級特大地震影響,放射性物質發(fā)生泄漏命雀。R本人自食惡果不足惜蒜哀,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吏砂。 院中可真熱鬧撵儿,春花似錦、人聲如沸狐血。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氛雪。三九已至房匆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浴鸿。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工井氢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岳链。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓花竞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掸哑。 傳聞我的和親對象是個殘疾皇子约急,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351