From 1194a839800e825b4b34e7c6863979f596de0530 Mon Sep 17 00:00:00 2001 From: Zaw Zaw Win Date: Wed, 17 May 2023 11:40:50 +0630 Subject: [PATCH 1/8] Create burmese.md --- burmese.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 burmese.md diff --git a/burmese.md b/burmese.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/burmese.md @@ -0,0 +1 @@ + From 0a5b52e0e5e1408473fcdf3aeec495a5b92706e3 Mon Sep 17 00:00:00 2001 From: Zaw Zaw Win Date: Wed, 17 May 2023 11:45:06 +0630 Subject: [PATCH 2/8] Update burmese.md --- burmese.md | 668 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 668 insertions(+) diff --git a/burmese.md b/burmese.md index 8b13789..7070fe5 100644 --- a/burmese.md +++ b/burmese.md @@ -1 +1,669 @@ +![Laravel best practices](/images/logo-english.png?raw=true) +You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app) + +Translations: + +[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol)) + +[Indonesia](indonesia.md) (by [P0rguy](https://github.com/p0rguy), [Doni Ahmad](https://github.com/donyahmd)) + +[한국어](https://github.com/xotrs/laravel-best-practices) (by [cherrypick](https://github.com/xotrs)) + +[日本語](japanese.md) (by [2bo](https://github.com/2bo)) + +[简体中文](chinese.md) (by [xiaoyi](https://github.com/Shiloh520)) + +[繁體中文](traditional-chinese.md) (by [woeichern](https://github.com/woeichern)) + +[ภาษาไทย](thai.md) (by [kongvut sangkla](https://github.com/kongvut)) + +[বাংলা](bangla.md) (by [Anowar Hossain](https://github.com/AnowarCST)) + +[فارسی](persian.md) (by [amirhossein baghaie](https://github.com/ohmydevops)) + +[Português](https://github.com/jonaselan/laravel-best-practices) (by [jonaselan](https://github.com/jonaselan)) + +[Українська](ukrainian.md) (by [Tenevyk](https://github.com/tenevyk)) + +[Русский](russian.md) + +[Tiếng Việt](https://chungnguyen.xyz/posts/code-laravel-lam-sao-cho-chuan) (by [Chung Nguyễn](https://github.com/nguyentranchung)) + +[Español](spanish.md) (by [César Escudero](https://github.com/cedaesca)) + +[Français](french.md) (by [Mikayil S.](https://github.com/mikayilsrt)) + +[Polski](polish.md) (by [Karol Pietruszka](https://github.com/pietrushek)) + +[Türkçe](turkish.md) (by [Burak](https://github.com/ikidnapmyself)) + +[Deutsch](german.md) (by [Sujal Patel](https://github.com/sujalpatel2209)) + +[Italiana](italian.md) (by [Sujal Patel](https://github.com/sujalpatel2209)) + +[Azərbaycanca](https://github.com/Maharramoff/laravel-best-practices-az) (by [Maharramoff](https://github.com/Maharramoff)) + +[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31)) + +[اردو](urdu.md) (by [RizwanAshraf1](https://github.com/RizwanAshraf1)) + +[Myanmar(Burmese)](burmese.md) (by [hareom284](https://github.com/hareom284)) +[![Laravel example app](/images/laravel-real-world-banner.png?raw=true)](https://github.com/alexeymezenin/laravel-realworld-example-app) + +## Contents + +[Single responsibility principle](#single-responsibility-principle) + +[Fat models, skinny controllers](#fat-models-skinny-controllers) + +[Validation](#validation) + +[Business logic should be in service class](#business-logic-should-be-in-service-class) + +[Don't repeat yourself (DRY)](#dont-repeat-yourself-dry) + +[Prefer to use Eloquent over using Query Builder and raw SQL queries. Prefer collections over arrays](#prefer-to-use-eloquent-over-using-query-builder-and-raw-sql-queries-prefer-collections-over-arrays) + +[Mass assignment](#mass-assignment) + +[Do not execute queries in Blade templates and use eager loading (N + 1 problem)](#do-not-execute-queries-in-blade-templates-and-use-eager-loading-n--1-problem) + +[Chunk data for data-heavy tasks](#chunk-data-for-data-heavy-tasks) + +[Comment your code, but prefer descriptive method and variable names over comments](#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](#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-config-and-language-files-constants-instead-of-text-in-the-code) + +[Use standard Laravel tools accepted by community](#use-standard-laravel-tools-accepted-by-community) + +[Follow Laravel naming conventions](#follow-laravel-naming-conventions) + +[Use shorter and more readable syntax where possible](#use-shorter-and-more-readable-syntax-where-possible) + +[Use IoC container or facades instead of new Class](#use-ioc-container-or-facades-instead-of-new-class) + +[Do not get data from the `.env` file directly](#do-not-get-data-from-the-env-file-directly) + +[Store dates in the standard format. Use accessors and mutators to modify date format](#store-dates-in-the-standard-format-use-accessors-and-mutators-to-modify-date-format) + +[Other good practices](#other-good-practices) + +### **Single responsibility principle** + +A class and a method should have only one responsibility. + +Bad: + +```php +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: + +```php +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](#contents) + +### **Fat models, skinny controllers** + +Put all DB related logic into Eloquent models. + +Bad: + +```php +public function index() +{ + $clients = Client::verified() + ->with(['orders' => function ($q) { + $q->where('created_at', '>', Carbon::today()->subWeek()); + }]) + ->get(); + + return view('index', ['clients' => $clients]); +} +``` + +Good: + +```php +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](#contents) + +### **Validation** + +Move validation from controllers to Request classes. + +Bad: + +```php +public function store(Request $request) +{ + $request->validate([ + 'title' => 'required|unique:posts|max:255', + 'body' => 'required', + 'publish_at' => 'nullable|date', + ]); + + ... +} +``` + +Good: + +```php +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](#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: + +```php +public function store(Request $request) +{ + if ($request->hasFile('image')) { + $request->file('image')->move(public_path('images') . 'temp'); + } + + ... +} +``` + +Good: + +```php +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](#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: + +```php +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: + +```php +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](#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. + +Bad: + +```sql +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: + +```php +Article::has('user.profile')->verified()->latest()->get(); +``` + +[🔝 Back to contents](#contents) + +### **Mass assignment** + +Bad: + +```php +$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: + +```php +$category->article()->create($request->validated()); +``` + +[🔝 Back to contents](#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): + +```blade +@foreach (User::all() as $user) + {{ $user->profile->name }} +@endforeach +``` + +Good (for 100 users, 2 DB queries will be executed): + +```php +$users = User::with('profile')->get(); + +@foreach ($users as $user) + {{ $user->profile->name }} +@endforeach +``` + +[🔝 Back to contents](#contents) + +### **Chunk data for data-heavy tasks** + +Bad: + +```php +$users = $this->get(); + +foreach ($users as $user) { + ... +} +``` + +Good: + +```php +$this->chunk(500, function ($users) { + foreach ($users as $user) { + ... + } +}); +``` + +[🔝 Back to contents](#contents) + +### **Prefer descriptive method and variable names over comments** + +Bad: + +```php +// Determine if there are any joins +if (count((array) $builder->getQuery()->joins) > 0) +``` + +Good: + +```php +if ($this->hasJoins()) +``` + +[🔝 Back to contents](#contents) + +### **Do not put JS and CSS in Blade templates and do not put any HTML in PHP classes** + +Bad: + +```javascript +let article = `{{ json_encode($article) }}`; +``` + +Better: + +```php + + +Or + +