alexeymezenin/laravel-best-practices
alexeymezenin/laravel-best-practices là một trong những repo phía máy chủ mà TopGit theo dõi, hiện có 12.3k sao. Laravel best practices
Tóm tắt dựng từ metadata GitHub của chính dự án — chưa có bài review TopGit. Trang sẽ tự động cập nhật khi bài review đầy đủ được xuất bản.
TopGit viết bài đầy đủ cho repo có nhiều sao nhất và được yêu cầu nhiều nhất. Trang này là snapshot trong thời gian chờ — xem README gốc ở tab READ ME.
Snapshot
Cộng tác viên hàng đầu
Xem cộng tác viên hàng đầu

You might also want to check out the real-world Laravel example application and Eloquent SQL reference
Translations:
Nederlands (by Protoqol)
Indonesia (by P0rguy, Doni Ahmad)
한국어 (by cherrypick)
日本語 (by 2bo)
简体中文 (by xiaoyi)
繁體中文 (by woeichern)
ภาษาไทย (by kongvut sangkla)
বাংলা (by Anowar Hossain)
فارسی (by amirhossein baghaie)
Português (by jonaselan)
Українська (by Tenevyk)
Русский
Tiếng Việt (by Chung Nguyễn)
Español (by César Escudero)
Français (by Mikayil S.)
Polski (by Karol Pietruszka)
Română (by als698)
Türkçe (by Burak)
Turkmen (by Artyom Osepyan)
Deutsch (by Sujal Patel)
Italiana (by Sujal Patel)
Azərbaycanca (by Maharramoff)
العربية (by ahmedsaoud31)
اردو (by RizwanAshraf1)
မြန်မာဘာသာ (by Kaung Zay Yan)

Contents
Single responsibility principle
Methods should do just one thing
Fat models, skinny controllers
Validation
Business logic should be in service class
Don't repeat yourself (DRY)
Prefer to use Eloquent over using Query Builder and raw SQL queries. Prefer collections over arrays
Mass assignment
Do not execute queries in Blade templates and use eager loading (N + 1 problem)
Chunk data for data-heavy tasks
Comment your code, but prefer descriptive method and variable names over comments
Do not put JS and CSS in Blade templates and do not put any HTML in PHP classes
Use config and language files, constants instead of text in the code
Use standard Laravel tools accepted by community
Follow Laravel naming conventions
Convention over configuration
Use shorter and more readable syntax where possible
Use IoC / Service container instead of new Class
Do not get data from the .env file directly
Store dates in the standard format. Use accessors and mutators to modify date format
Do not use DocBlocks
Other good practices
Single responsibility principle
A class should have only one responsibility.
Bad:
public function update(Request $request): string
{
$validated = $request->validate([
'title' => 'required|max:255',
'events' => 'required|array:date,type'
]);
foreach ($request->events as $event) {
$date = $this->carbon->parse($event['date'])->toString();
$this->logger->log('Update event ' . $date . ' :: ' . $);
}
$this->event->updateGeneralEvent($request->validated());
return back();
}
Good:
public function update(UpdateRequest $request): string
{
$this->logService->logEvents($request->events);
$this->event->updateGeneralEvent($request->validated());
return back();
}
🔝 Back to contents
Methods should do just one thing
A function should do just one thing and do it well.
Bad:
public function getFullNameAttribute(): string
{
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;
}
}
Good:
public function getFullNameAttribute(): string
{
return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}
public function isVerifiedClient(): bool
{
return auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified();
}
public function getFullNameLong(): string
{
return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}
public function getFullNameShort(): string
{
return $this->first_name[0] . '. ' . $this->last_name;
}
🔝 Back to contents
Fat models, skinny controllers
Put all DB related logic into Eloquent models.
Bad:
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
Good:
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders(): Collection
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
🔝 Back to contents
Validation
Move validation from controllers to Request classes.
Bad:
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
Good:
public function store(PostRequest $request)
{
...
}
class PostRequest extends Request
{
public function rules(): array
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
];
}
}
🔝 Back to contents
Business logic should be in service class
A controller must have only one responsibility, so move business logic from controllers to service classes.
Bad:
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
Good:
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image): void
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
🔝 Back to contents
Don't repeat yourself (DRY)
Reuse code when you can. SRP is helping you to avoid duplication. Also, reuse Blade templates, use Eloquent scopes etc.
Bad:
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();
}
Good:
public function scopeActive($q)
{
return $q->where('verified', true)->whereNotNull('deleted_at');
}
public function getActive(): Collection
{
return $this->active()->get();
}
public function getArticles(): Collection
{
return $this->whereHas('user', function ($q) {
$q->active();
})->get();
}
🔝 Back to contents
Prefer to use Eloquent over using Query Builder and raw SQL queries. Prefer collections over arrays
Eloquent allows you to write readable and maintainable code. Also, Eloquent has great built-in tools like soft deletes, events, scopes etc. You may want to check out Eloquent to SQL reference
Bad:
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
Good:
Article::has('user.profile')->verified()->latest()->get();
🔝 Back to contents
Mass assignment
Bad:
$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();
Good:
$category->article()->create($request->validated());
🔝 Back to contents
Do not execute queries in Blade templates and use eager loading (N + 1 problem)
Bad (for 100 users, 101 DB queries will be executed):
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
Good (for 100 users, 2 DB queries will be executed):
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
🔝 Back to contents
Chunk data for data-heavy tasks
Bad:
$users = $this->get();
foreach ($users as $user) {
...
}
Good:
$this->chunk(500, function ($users) {
foreach ($users as $user) {
...
}
});
🔝 Back to contents
Prefer descriptive method and variable names over comments
Bad:
// Determine if there are any joins
if (count((array) $builder->getQuery()->joins) > 0)
Good:
if ($this->hasJoins())
🔝 Back to contents
Do not put JS and CSS in Blade templates and do not put any HTML in PHP classes
Bad:
let article = `{{ json_encode($article) }}`;
Better:
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
In a Javascript file:
let article = $('#article').val();
The best way is to use specialized PHP to JS package to transfer the data.
🔝 Back to contents
Use config and language files, constants instead of text in the code
Bad:
public function isNormal(): bool
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
Good:
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
🔝 Back to contents
Use standard Laravel tools accepted by community
Prefer to use built-in Laravel functionality and community packages instead of using 3rd party packages and tools. Any developer who will work with your app in the future will need to learn new tools. Also, chances to get help from the Laravel community are significantly lower when you're using a 3rd party package or tool. Do not make your client pay for that.
| Task | Standard tools | 3rd party tools |
|---|---|---|
| Authorization | Policies | Entrust, Sentinel and other packages |
| Compiling assets | Laravel Mix, Vite | Grunt, Gulp, 3rd party packages |
| Development Environment | Laravel Sail, Homestead | Docker |
| Deployment | Laravel Forge | Deployer and other solutions |
| Unit testing | PHPUnit, Mockery | Phpspec, Pest |
| Browser testing | Laravel Dusk | Codeception |
| DB | Eloquent | SQL, Doctrine |
| Templates | Blade | Twig |
| Working with data | Laravel collections | Arrays |
| Form validation | Request classes | 3rd party packages, validation in controller |
| Authentication | Built-in | 3rd party packages, your own solution |
| API authentication | Laravel Passport, Laravel Sanctum | 3rd party JWT and OAuth packages |
| Creating API | Built-in | Dingo API and similar packages |
| Working with DB structure | Migrations | Working with DB structure directly |
| Localization | Built-in | 3rd party packages |
| Realtime user interfaces | Laravel Echo, Pusher | 3rd party packages and working with WebSockets directly |
| Generating testing data | Seeder classes, Model Factories, Faker | Creating testing data manually |
| Task scheduling | Laravel Task Scheduler | Scripts and 3rd party packages |
| DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB |
🔝 Back to contents
Follow Laravel naming conventions
Follow PSR standards.
Also, follow naming conventions accepted by Laravel community:
| What | How | Good | Bad |
|---|---|---|---|
| Controller | singular | ArticleController | |
| Route | plural | articles/1 | |
| Route name | snake_case with dot notation | users.show_active | |
| Model | singular | User | |
| hasOne or belongsTo relationship | singular | articleComment | |
| All other relationships | plural | articleComments | |
| Table | plural | article_comments | |
| Pivot table | singular model names in alphabetical order | article_user | |
| Table column | snake_case without model name | meta_title | |
| Model property | snake_case | $model->created_at | |
| Foreign key | singular model name with _id suffix | article_id | |
| Primary key | - | id | |
| Migration | - | 2017_01_01_000000_create_articles_table | |
| Method | camelCase | getAll | |
| Method in resource controller | table | store | |
| Method in test class | camelCase | testGuestCannotSeeArticle | |
| Variable | camelCase | $articlesWithAuthor | |
| Collection | descriptive, plural | $activeUsers = User::active()->get() | |
| Object | descriptive, singular | $activeUser = User::active()->first() | |
| Config and language files index | snake_case | articles_enabled | |
| View | kebab-case | show-filtered.blade.php | |
| Config | snake_case | google_calendar.php | |
| Contract (interface) | adjective or noun | AuthenticationInterface | |
| Trait | adjective | Notifiable | |
| Trait (PSR) | adjective | NotifiableTrait | |
| Enum | singular | UserType | |
| FormRequest | singular | UpdateUserRequest | |
| Seeder | singular | UserSeeder |
🔝 Back to contents
Convention over configuration
As long as you follow certain conventions, you do not need to add additional configuration.
Bad:
// Table name 'Customer'
// Primary key 'customer_id'
class Customer extends Model
{
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $table = 'Customer';
protected $primaryKey = 'customer_id';
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class, 'role_customer', 'customer_id', 'role_id');
}
}
Good:
// Table name 'customers'
// Primary key 'id'
class Customer extends Model
{
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
}
🔝 Back to contents
Use shorter and more readable syntax where possible
Bad:
$request->session()->get('cart');
$request->input('name');
Good:
session('cart');
$request->name;
More examples:
| Common syntax | Shorter and more readable syntax |
|---|---|
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) ? null : $object->relation->id | optional($object->relation)->id (in PHP 8: $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') |
🔝 Back to contents
Use IoC / Service container instead of new Class
new Class syntax creates tight coupling between classes and complicates testing. Use IoC container or facades instead.
Bad:
$user = new User;
$user->create($request->validated());
Good:
public function __construct(protected User $user) {}
...
$this->user->create($request->validated());
🔝 Back to contents
Do not get data from the .env file directly
Pass the data to config files instead and then use the config() helper function to use the data in an application.
Bad:
$apiKey = env('API_KEY');
Good:
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
🔝 Back to contents
Store dates in the standard format. Use accessors and mutators to modify date format
A date as a string is less reliable than an object instance, e.g. a Carbon-instance. It's recommended to pass Carbon objects between classes instead of date strings. Rendering should be done in the display layer (templates):
Bad:
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
Good:
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
// Blade view
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->format('m-d') }}
🔝 Back to contents
Do not use DocBlocks
DocBlocks reduce readability. Use a descriptive method name and modern PHP features like return type hints instead.
Bad:
/**
* The function checks if given string is a valid ASCII string
*
* @param string $string String we get from frontend which might contain
* illegal characters. Returns True is the string
* is valid.
*
* @return bool
* @author John Smith
*
* @license GPL
*/
public function checkString($string)
{
}
Good:
public function isValidAsciiString(string $string): bool
{
}
🔝 Back to contents
Other good practices
Avoid using patterns and tools that are alien to Laravel and similar frameworks (i.e. RoR, Django). If you like Symfony (or Spring) approach for building apps, it's a good idea to use these frameworks instead.
Never put any logic in routes files.
Minimize usage of vanilla PHP in Blade templates.
Use in-memory DB for testing.
Do not override standard framework features to avoid problems related to updating the framework version and many other issues.
Use modern PHP syntax where possible, but don't forget about readability.
Avoid using View Composers and similar tools unless you really know what you're doing. In most cases, there is a better way to solve the problem.
🔝 Back to contents
Repo liên quan
Node.js Best Practices, maintained at goldbergyoni/nodebestpractices, is a curated checklist of more than 80 recommendations for building Node.js applications, organized into eight categories from project architecture to Docker. Each entry combines a short recommendation with an explanation of the risk of skipping it and a link to a deeper write-up, rather than being a plain list of links.
Laravel is an open-source PHP web application framework maintained at laravel/laravel, bundling a routing engine, dependency injection, the Eloquent ORM, schema migrations, queue processing, and event broadcasting into one framework. It's MIT-licensed, documents support for AI coding agents through the separate Laravel Boost package, and points to Laracasts and Laravel Learn for getting started.
Public APIs is a community-curated GitHub repository listing free, publicly accessible APIs across a wide range of categories, with auth type, HTTPS, and CORS noted for each entry. It's a browsable reference, not a library to install.
Awesome Python is a curated list maintained at vinta/awesome-python that groups Python frameworks, libraries, tools, and other resources into 14 categories, from AI & ML to Security and Other. The README calls it an opinionated guide rather than an exhaustive one, and points readers to a companion site, awesome-python.com, for searching and filtering entries instead of scrolling the raw file.
Trả lời nhanh
alexeymezenin/laravel-best-practices có bao nhiêu sao?
alexeymezenin/laravel-best-practices có 12.3k sao GitHub — tải lại trang để xem số mới nhất, hoặc xem trực tiếp github.com/alexeymezenin/laravel-best-practices. TopGit phản chiếu số sao của GitHub nhưng không cam kết đến từng phút.
alexeymezenin/laravel-best-practices có phải mã nguồn mở không?
TopGit chưa ghi nhận license cho alexeymezenin/laravel-best-practices. Phần lớn repo public trên GitHub là mã nguồn mở, nhưng điều khoản khác nhau từng repo — mở file LICENSE để xác nhận.
alexeymezenin/laravel-best-practices còn đang phát triển không?
Commit gần nhất trên alexeymezenin/laravel-best-practices là 1.3 năm trước (theo timestamp GitHub). Repo có 2.4k fork — một chỉ báo về mức độ quan tâm của cộng đồng.
alexeymezenin/laravel-best-practices là gì?
alexeymezenin/laravel-best-practices (alexeymezenin/laravel-best-practices) là dự án đa ngôn ngữ trên GitHub. Theo mô tả gốc: Laravel best practices
alexeymezenin/laravel-best-practices so với các dự án Backend khác thế nào?
alexeymezenin/laravel-best-practices được TopGit xếp vào nhóm Backend, với 12.3k sao GitHub. Xem trang chủ đề Backend trên TopGit để so sánh với các dự án tương tự theo số sao và mức độ hoạt động.
Đọc thêm về alexeymezenin/laravel-best-practices ở đâu?
Trang TopGit này là một snapshot — tab "Readme" hiển thị nguyên văn README của repo (đã bỏ link, giữ ảnh). Repo GitHub ở github.com/alexeymezenin/laravel-best-practices là nguồn chính thức.
Đọc đầy đủ README ở tab phía trên.
Chưa chắc laravel-best-practices có hợp với bạn?
Để ChatGPT, Claude hoặc Perplexity tìm hiểu giúp — bấm bên dưới và xem AI nói gì về laravel-best-practices.