Hi các bạn,
Theo tư tưởng của Taylor – web development should be fun and easy to learn, thì mình nên follow cái này để làm code của chúng ta đẹp đẽ thân thiện hơn.
Ở bài này, mình sẽ cho bạn 1 ít mắm muối vào cái custom Request class của bạn, để nó ngon lành hơn nè.
Let’s roll.
Retrieve Other Models
Sự thật là khi làm 1 project, $this->route('model')
thì không phải lúc nào cũng đủ, có khi ta cần load thêm 2-3 models nữa từ Request, vd:
articles/{articleId}/set-category
POST:
- category_uuid – UUID của category cần set cho Article
Vậy khi đó mình sẽ có cái method rules
như sau:
<?php
class ArticleSetCategoryRequest extends FormRequest
{
//...
public function rules(): array
{
return [
'category_uuid' => 'required|exists:categories,uuid',
];
}
}
Thông thường, trong Controller, ta sẽ load model như vầy:
class ArticleController extends Controller
{
public function setCategory(Article $article, ArticleSetCategoryRequest $request): JsonResponse
{
$category = Category::findByUuid($request->input('category_uuid'));
//...
}
}
Nhìn hổng clean lắm nhỉ, nhưng nếu ta bỏ qua Request class, nó sẽ như sau:
class ArticleSetCategoryRequest extends FormRequest
{
public function getCategory(): Category
{
return Category::findByUuid($request->input('category_uuid'));
}
Và giờ ở Controller, ta lấy Category
ra:
class ArticleController extends Controller
{
public function setCategory(Article $article, ArticleSetCategoryRequest $request): JsonResponse
{
$category = $request->getCategory();
$article->categories()->sync($category);
}
}
Better hơn, nhỉ? Vì khi này ta đã bưng logic qua Request và nó nên vậy, Request nên cung cấp đủ dữ liệu cho Controller trước khi xử lý.
P/s: ngoài ra bạn cũng nên implement 1 cái short-cache ở đây, nếu bạn có ý định getCategory
liên tục, điều này sẽ tránh dc mỗi lần get lại tốn 1 query xuống db => slow => bad practice.
Ngoài ra, mình sure kèo Category
thay vì ?Category
(nullable-type) bởi vì rules
của mình có required category, nên nếu mà nó missing => lỗi 422 rồi.
class ArticleSetCategoryRequest extends FormRequest
{
private Category $category;
public function getCategory(): Category
{
return $this->category ??= Category::findByUuid($request->input('category_uuid'));
}
}
Wants
Như tên của nó, Request từ client muốn BE bên mình trả về cái gì?
Ví dụ, Laravel có cái này: wantsJson
, nếu mà nó returns true
thì Response đó, Laravel sẽ auto parse về JSON.
Từ đó ta adapt cái terms này để làm Request của chúng ta đẹp hơn, một vài ví dụ cho bạn:
wantsArticles
Ví dụ bạn đang làm 1 endpoint GET categories/{id}
, thông thường bạn chả cần load articles làm gì. Nhưng vd 1 ngày đẹp trời bạn cần load articles của category, thì Request của bạn sẽ như sau:
class CategoryShowRequest extends FormRequest
{
public function wantsArticles(): bool
{
return (bool) $this->input('load_articles');
}
}
Và ở Controller:
class CategoryController extends Controller
{
public function show(Category $category, CategoryShowRequest $request): JsonResponse
{
if ($request->wantsArticles()) {
$category->load(['articles']);
}
//...
}
}
Rất clean, nhỉ?
wantsSortByHighView
Sort theo lượt views nhiều của Article?
Request:
class ArticleIndexRequest extends FormRequest
{
public function wantsSortByHighView(): bool
{
return (bool) $this->input('sort_by_high_views');
}
}
Controller:
class ArticleController extends Controller
{
public function index(ArticleIndexRequest $request): JsonResponse
{
$articlesQuery = Article::query();
$articlesQuery->when(
$request->wantsSortByHighView(),
fn (Builder $q) => $q->orderBy('views', 'DESC')
);
//...
}
}
// Đây là 2 ví dụ mình suy nghĩ ra dc, bạn có thể apply tương tự cho cases của bạn nhé.
Conclusions
Đây là 2 cái nho nhỏ để giúp code bạn đẹp hơn và dễ đọc hơn, để có gì có gì hay mình update típ nhá.
Happy weekend, folks!