Laravel 你應該知道的幾個最佳實踐

MArtian發表於2022-04-22

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

一些常用的查詢,應該把它們封裝到模型中,控制器不應該知道太多事情。

不推薦:

public function index()
{
    $clients = Client::verified()
        ->with(['orders' => function ($q) {
            $q->where('created_at', '>', Carbon::today()->subWeek());
        }])
        ->get();

    return view('index', ['clients' => $clients]);
}

推薦使用:

// Controller
public function index()
{
    return view('index', ['clients' => $this->client->getWithNewOrders()]);
}

// Model
Class Client extends Model
{
    public function getWithNewOrders()
    {
        return $this->verified()
            ->with(['orders' => function ($q) {
                $q->where('created_at', '>', Carbon::today()->subWeek());
            }])
            ->get();
    }
}

本著單一職責,我們應該把控制器中的業務邏輯抽離到 Service 類裡。

不推薦:

public function store(Request $request)
{
    if ($request->hasFile('image')) {
        $request->file('image')->move(public_path('images') . 'temp');
    }

    ....
}

推薦使用:

// Controller
public function store(Request $request)
{
    $this->articleService->handleUploadedImage($request->file('image'));
    ....
}

// Service
class ArticleService
{
    public function handleUploadedImage($image)
    {
        if (!is_null($image)) {
            $image->move(public_path('images') . 'temp');
        }
    }
}

如果你踐行 單一職責,其實已經很大程度上避免了 DRY。

不推薦:

public function getActive()
{
    return $this->where('verified', 1)->get();
}

public function getArticles()
{
    return $this->whereHas('user', function ($q) {
            $q->where('verified', 1);
        })->get();
}

推薦使用:

public function scopeActive($q)
{
    return $q->where('verified', 1);
}

public function getActive()
{
    return $this->active()->get();
}

public function getArticles()
{
    return $this->whereHas('user', function ($q) {
            $q->active();
        })->get();
}

Eloquent 編寫的查詢可讀性比原生 SQL 要好很多。而且 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();

最差的:

if (count((array) $builder->getQuery()->joins) > 0)

好一點的:

// 判斷是否存在連線
if (count((array) $builder->getQuery()->joins) > 0)

最佳的:
使用方法來封裝它,並且起一個一目瞭然的名字。

if ($this->hasJoins())

不推薦:

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

env() 函式在配置檔案之外使用。如果配置被快取,你將獲取不到它。

不推薦:

$apiKey = env('API_KEY');

推薦使用:

// 配置 config/api.php
'key' => env('API_KEY'),

// 獲取
$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 }}

都是一些老生常談的問題了,整理一下,希望對你有幫助。
enjoy :tada:

本作品採用《CC 協議》,轉載必須註明作者和本文連結
我從未見過一個早起、勤奮、謹慎,誠實的人抱怨命運。

相關文章