Laravel best practices
Nguyên tắc Đơn nhiệm - Single responsibility principle
Class và method chỉ nên chịu 1 trách nhiệm. Khi có các xử lý phức tạp thì nên tách ra thành các class, method mới để chịu trách nhiệm cho phần xử lý đó.
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;
}
}
Đoạn code trên có quá nhiều đoạn xử lý phức tạp nên được tách ra thành các function nhỏ hơn để chịu các trách nhiệm tương ứng.
public function getFullNameAttribute()
{
return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}
public function isVerifiedClient()
{
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;
}
Validation
Không thực hiện việc validate trong controller như dưới đây:
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
....
}
Phải tách riêng thành 1 class chịu trách nhiệm validate như sau:
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',
];
}
}
Don’t repeat yourself (DRY)
Khi có các đoạn code xử lý mà bị lặp lại từ 2 lần trở lên cần xem xét lại để viết code sao cho có thể thể dễ dàng tái sử dụng, tránh việc lặp code. Có thể tận dụng sức mạnh của Blade Templates, Eloquent scopes,…
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();
}
Dễ dàng nhận thấy đoạn code ->where('verified', 1)->whereNotNull('deleted_at')
bị lặp và có thể viết lại như sau:
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();
}
Mass assignment
Tận dụng tối đa Mass Assignment trong mọi trường hợp để tối giản code và tăng cường tính bảo mật.
$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();
Thay vì gán từng giá trị cho các property tương ứng chúng ta làm đơn giản hơn
$category->article()->create($request->validated());
Eager Loading
Sử dụng Eager Loading để tránh bị (N + 1) query trong các trường hợp cần truy xuất dữ liệu của các quan hệ.
$users = User::get();
...
@foreach ($users as $user)
@endforeach
Trong trường hợp trên khi truy xuất thông tin profile của 1 user thông qua quan hệ thì mỗi user sẽ mất 1 câu query. Chúng ta có thể viết lại như sau:
$users = User::with('profile')->get();
...
@foreach ($users as $user)
@endforeach
Không viết JS và CSS trong Blade templates, không viết HTML trong PHP class
Không viết đoạn code JS trong các view
let article = ``;
Nên gán giá trị vào các input
kiểu hidden
hoặc các attribute
và lấy giá trị thông qua các input và attribute này
<input id="article" type="hidden" value="@json($article)">
Or
<button class="js-fav-article" data-article="@json($article)"><button>
Sử dụng các giá trị lấy từ config hoặc các constants thay vì hardcode
public function isNormal()
{
return $article->type === 'normal';
}
public function isAdmin()
{
return $user->type === 1;
}
return back()->with('message', 'Your article has been added!');
Không sử dụng string
hoặc number
để kiểm tra các điều kiện và hardcode các đoạn text mà sử dụng các const
và lấy
text từ trong các language files
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
public function isAdmin()
{
return $user->type === USER::TYPE_ADMIN;
}
return back()->with('message', __('app.article_added'));
Không lấy dữ liệu trực tiếp từ .env
$apiKey = env('API_KEY');
Thay vì lấy dữ liệu trực tiếp từ .env
truyền data sang config
tương ứng và sau đấy dùng hàm config()
để lấy giá trị.
Nên set các giá trị mặc định nếu có.
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');