Showing preview only (425K chars total). Download the full file or copy to clipboard to get everything.
Repository: alexeymezenin/laravel-best-practices
Branch: master
Commit: 2bdce1396b29
Files: 23
Total size: 411.5 KB
Directory structure:
gitextract_g1v8989h/
├── README.md
├── arabic.md
├── bangla.md
├── burmese.md
├── chinese.md
├── french.md
├── german.md
├── images/
│ └── logo-language.psd
├── indonesia.md
├── italian.md
├── japanese.md
├── pashto.md
├── persian.md
├── polish.md
├── romanian.md
├── russian.md
├── spanish.md
├── thai.md
├── traditional-chinese.md
├── turkish.md
├── turkmen.md
├── ukrainian.md
└── urdu.md
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app) and [Eloquent SQL reference](https://github.com/alexeymezenin/eloquent-sql-reference)
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))
[Română](romanian.md) (by [als698](https://github.com/als698))
[Türkçe](turkish.md) (by [Burak](https://github.com/ikidnapmyself))
[Turkmen](turkmen.md) (by [Artyom Osepyan](https://github.com/artengin))
[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))
[မြန်မာဘာသာ](burmese.md) (by [Kaung Zay Yan](https://github.com/KaungZayY))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Contents
[Single responsibility principle](#single-responsibility-principle)
[Methods should do just one thing](#methods-should-do-just-one-thing)
[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](#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)
[Convention over configuration](#convention-over-configuration)
[Use shorter and more readable syntax where possible](#use-shorter-and-more-readable-syntax-where-possible)
[Use IoC / Service container instead of new Class](#use-ioc--service-container-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)
[Do not use DocBlocks](#do-not-use-docblocks)
[Other good practices](#other-good-practices)
### **Single responsibility principle**
A class should have only one responsibility.
Bad:
```php
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:
```php
public function update(UpdateRequest $request): string
{
$this->logService->logEvents($request->events);
$this->event->updateGeneralEvent($request->validated());
return back();
}
```
[🔝 Back to contents](#contents)
### **Methods should do just one thing**
A function should do just one thing and do it well.
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. You may want to check out [Eloquent to SQL reference](https://github.com/alexeymezenin/eloquent-sql-reference)
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
<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:
```javascript
let article = $('#article').val();
```
The best way is to use specialized PHP to JS package to transfer the data.
[🔝 Back to contents](#contents)
### **Use config and language files, constants instead of text in the code**
Bad:
```php
public function isNormal(): bool
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Good:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 Back to contents](#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](#contents)
### **Follow Laravel naming conventions**
Follow [PSR standards](https://www.php-fig.org/psr/psr-12/).
Also, follow naming conventions accepted by Laravel community:
What | How | Good | Bad
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Route name | snake_case with dot notation | users.show_active | ~~users.show-active, show-active-users~~
Model | singular | User | ~~Users~~
hasOne or belongsTo relationship | singular | articleComment | ~~articleComments, article_comment~~
All other relationships | plural | articleComments | ~~articleComment, article_comments~~
Table | plural | article_comments | ~~article_comment, articleComments~~
Pivot table | singular model names in alphabetical order | article_user | ~~user_article, articles_users~~
Table column | snake_case without model name | meta_title | ~~MetaTitle; article_meta_title~~
Model property | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | singular model name with _id suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Method | camelCase | getAll | ~~get_all~~
Method in resource controller | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Method in test class | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptive, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptive, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Config and language files index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjective or noun | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjective | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 Back to contents](#contents)
### **Convention over configuration**
As long as you follow certain conventions, you do not need to add additional configuration.
Bad:
```php
// 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:
```php
// Table name 'customers'
// Primary key 'id'
class Customer extends Model
{
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
}
```
[🔝 Back to contents](#contents)
### **Use shorter and more readable syntax where possible**
Bad:
```php
$request->session()->get('cart');
$request->input('name');
```
Good:
```php
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](#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:
```php
$user = new User;
$user->create($request->validated());
```
Good:
```php
public function __construct(protected User $user) {}
...
$this->user->create($request->validated());
```
[🔝 Back to contents](#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:
```php
$apiKey = env('API_KEY');
```
Good:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝 Back to contents](#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:
```php
{{ 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:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
// Blade view
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->format('m-d') }}
```
[🔝 Back to contents](#contents)
### **Do not use DocBlocks**
DocBlocks reduce readability. Use a descriptive method name and modern PHP features like return type hints instead.
Bad:
```php
/**
* 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:
```php
public function isValidAsciiString(string $string): bool
{
}
```
[🔝 Back to contents](#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](#contents)
================================================
FILE: arabic.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
## <p dir="rtl">الترجمات</p>
[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol))
[한국어](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))
[ภาษาไทย](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))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## <p dir="rtl">الفهرس</p>
[<p dir="rtl">نمط المسؤولية الواحدة</p>](#1)
[<p dir="rtl">شيفرة أكثر في النماذج، شيفرة أقل في المتحكمات</p>](#2)
[<p dir="rtl">التحقق</p>](#3)
[<p dir="rtl">الشيفرات المنطقية يجب أن تكون في فئة خادمة منفصلة</p>](#4)
[<p dir="rtl">لا تكرر نفس الشيفرة</p>](#5)
،
[<p dir="rtl">يفضل استخدام نظام التعامل مع قواعد البيانات المسمى بـEloquent بدل استخدام باني الإستعلامات Query Builder أو الاستخدام المباشر لأوامر الإستعلامات SQL عبر raw، ويفضل استخدام المجموعات بدل المصفوفات</p>](#6)
[<p dir="rtl">تقليص المهام</p>](#7)
[<p dir="rtl">لا تقم بتنفيذ الإستعلامات داخل ملفات blade واستخدم التحميل الحثيث مشكلة (N+1)</p>](#8)
[<p dir="rtl">اضف التعليقات للشيفرة ويفضل استخدام صيغ التعليقات القياسية للمتغيرات والخواص والقيم المعادة إلخ</p>](#9)
[<p dir="rtl">لا تضع شيفرات js و css داخل ملفات Blade ولا تضع أي ششفرات HTML في فئات php</p>](#10)
[<p dir="rtl">استخدم ملفات الإعدادت واللغات، والثوابت بدلاً من النص داخل الشيفرة</p>](#11)
[<p dir="rtl">استخدم الأدوات القياسية المعتمدة من مجتمع لارافيل</p>](#12)
[<p dir="rtl">اتبع طريقة لارافيل في التسميات</p>](#13)
[<p dir="rtl">استخدم شيفرة أقصر قابلة للقراءة والفهم السريع قدر المستطاع</p>](#14)
[<p dir="rtl">استخدم الحاويات أو الواجهات بدلاً من الفئات الجديدة</p>](#15)
[<p dir="rtl">لا تقم بجلب البيانات من ملف `.env`</p>](#16)
[<p dir="rtl">احفظ البيانات في الشكل القياسي. استخدم المسترجعات والمُعدلات في تعديل شكل صيغة التاريخ</p>](#17)
[<p dir="rtl">ممارسات جيدة أخرى</p>](#18)
### <p dir="rtl">1</p>
### **<p dir="rtl">نمط المسئولية الواحدة</p>**
<p dir="rtl">وظيفة الفئة والطريقة يجب أن تكون مسئولية واحدة فقط، بمعنى آخر يجب ألا تكون الفئة أو الطريقة متعددة المهام ويجب أن تختص بمهمة واحدة فقط</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```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;
}
}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```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;
}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">2</p>
### **<p dir="rtl">شيفرة أكثر في النماذج، شيفرة أقل في المتحكمات</p>**
<p dir="rtl">ضع كل الشيفرات الخاصة بالتعامل مع قواعد البيانات في فئات خاصة منفصلة ولا تضعها في المتحكمات</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">3</p>
### **<p dir="rtl">التحقق</p>**
<p dir="rtl">انقل شيفرات التحقق من المتحكمات إلى فئات الطلبات Request classes</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
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',
];
}
}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">4</p>
### **<p dir="rtl">الشيفرات المنطقية يجب أن تكون في فئة خادمة منفصلة</p>**
<p dir="rtl">المتحكم يجب أن يكون له مسئولية واحدة فقط، أنقل الشيفرات المنطقية لفئات خادمة منفصلة</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">5</p>
### **<p dir="rtl">لا تكرر نفس الشيفرة</p>**
<p dir="rtl">أعد استخدام نفس الشيفرة قدر المستطاع ولا تقم بإعادة كتابتها، سيساعدك هذا على عدم وجود أكثر من شيفرة لتنفيذ نفس المهمة، وإعادة استخدام قوالب blade وفئات التعامل مع قواعد البيانات Eloquent</p>
<p dir="rtl">مثال استخدم scope في فئات التعامل مع قواعد البيانات Eloquent</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```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();
}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
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();
}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">6</p>
### **<p dir="rtl">يفضل استخدام نظام التعامل مع قواعد البيانات المسمى بـEloquent بدل استخدام باني الإستعلامات Query Builder أو الاستخدام المباشر لأوامر الإستعلامات SQL عبر raw، ويفضل استخدام المجموعات بدل المصفوفات</p>**
<p dir="rtl">Eloquent يجعلك تكتب شيفرة قابلة للقراءة والصيانة. وأيضاً، Eloquent يحتوي على أدوات وخواص داخلية على سبيل الذكر: الحذف الناعم والأحداث والنطاقات إلخ...</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```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
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
Article::has('user.profile')->verified()->latest()->get();
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">7</p>
### **<p dir="rtl">تقليص المهام</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```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();
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
$category->article()->create($request->validated());
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">8</p>
### **<p dir="rtl">لا تقم بتنفيذ الإستعلامات داخل ملفات blade واستخدم التحميل الحثيث مشكلة (N+1)</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
<p dir="rtl">~لعدد 100 مستخدم سيُنفذ 101 استعلام على قاعدة البيانات</p>
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
<p dir="rtl">✔️ طريقة جيدة:</p>
<p dir="rtl">~لعدد 100 مستخدم سيُنفذ 2 استعلام فقط على قاعدة البيانات~</p>
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">9</p>
### **<p dir="rtl">اضف التعليقات للشيفرة، ويفضل استخدام صيغ التعليقات القياسية للمتغيرات والخواص والقيم المعادة إلخ</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
<p dir="rtl">طريقة أفضل:</p>
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
if ($this->hasJoins())
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">10</p>
### **<p dir="rtl">لا تضع شيفرات js و css داخل ملفات Blade ولا تضع أي شيفرات HTML في فئات php</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```javascript
let article = `{{ json_encode($article) }}`;
```
<p dir="rtl">✔️ طريقة أفضل:</p>
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
في ملف جافا سكريبت:
```javascript
let article = $('#article').val();
```
<p dir="rtl">الطريقة الأفضل هي استخدام الحزم الخاصة بنقل البيانات من PHP إلى جافا سكريبت.</p>
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">11</p>
### **<p dir="rtl">استخدم ملفات الإعدادت واللغات، والثوابت بدلاً من النص داخل الشيفرة</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">12</p>
### **<p dir="rtl">استخدم الأدوات القياسية المعتمدة من مجتمع لارافيل</p>**
<p dir="rtl">يفضل استخدام الأدوات المدمجة مع إطار عمل لارافيل والحزم المقترحة من مجتمع لارفيل بدل استخدام غيرها، أي مطور سيعمل على تطبيقك في وقت لاحق سيحتاج إلى تعلم تلك الأدوات التي لا يشيع استخدامها في تطبيقات لارافيل، وأيضاً أطلب المساعدة من مجتمع لارافيل عندما تقرر الإعتماد على أحد الأدوات أو الحزم، ولا تجعل عميلك يدفع مقابل ذلك. </p>
الوظيفة | الأدوات القياسية | أدوات الطرف الثالث
------------ | ------------- | -------------
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
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">13</p>
### **<p dir="rtl">اتبع طريقة لارافيل في التسميات</p>**
<p dir="rtl">راجع <a href="http://www.php-fig.org/psr/psr-2">PSR standards</a></p>
<p dir="rtl">وأيضا، راجع اصطلاح التسميات المقبول من جهه مجتمع لارافيل:</p>
ماذا | كيف | جيدة | سيئة
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Route name | snake_case with dot notation | users.show_active | ~~users.show-active, show-active-users~~
Model | singular | User | ~~Users~~
hasOne or belongsTo relationship | singular | articleComment | ~~articleComments, article_comment~~
All other relationships | plural | articleComments | ~~articleComment, article_comments~~
Table | plural | article_comments | ~~article_comment, articleComments~~
Pivot table | singular model names in alphabetical order | article_user | ~~user_article, articles_users~~
Table column | snake_case without model name | meta_title | ~~MetaTitle; article_meta_title~~
Model property | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | singular model name with _id suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Method | camelCase | getAll | ~~get_all~~
Method in resource controller | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Method in test class | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptive, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptive, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Config and language files index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjective or noun | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjective | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">14</p>
### **<p dir="rtl">استخدم شيفرة أقصر قابلة للقراءة والفهم السريع قدر المستطاع</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```php
$request->session()->get('cart');
$request->input('name');
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
session('cart');
$request->name;
```
<p dir="rtl">أمثلة أكثر:</p>
جمل مركبة | جمل أقصر وأكثر قابلية للقراءة
------------ | -------------
`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`
`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')`
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">15</p>
### **<p dir="rtl">استخدم الحاويات أو الواجهات بدلاً من الفئات الجديدة</p>**
<p dir="rtl">إنشاء فئات جديدة يخلق شيئا من التشويش بين الفئات ويعقد عملة الإختبار، الأفضل الإعتماد على الحاويات أو الواجهات في هذا الأمر</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```php
$user = new User;
$user->create($request->validated());
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">16</p>
### **<p dir="rtl">لا تقم بجلب البيانات من ملف `.env` مباشرة</p>**
<p dir="rtl">مرر البيانات لملف الإعدادت ومن ثَم استخدم الدالة المساعدة `config()` لاستخدامها في جلب البيانات المخزنة في ملف الإعدادت داخل تطبيقك.</p>
<p dir="rtl">❌ طريقة سيئة:</p>
```php
$apiKey = env('API_KEY');
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">17</p>
### **<p dir="rtl">خزن التواريخ بأشكالها القياسية، واستخدم المسترجعات والمُعدلات لتعديل صيغة التواريخ كما تريد.</p>**
<p dir="rtl">❌ طريقة سيئة:</p>
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
<p dir="rtl">✔️ طريقة جيدة:</p>
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// ملف العرض
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
### <p dir="rtl">18</p>
### **<p dir="rtl">ممارسات جيدة أخرى</p>**
<p dir="rtl">لا تضع أي شيفرة برمجية في ملفات الموجهات.</p>
<p dir="rtl">قلل من استخدامك الشيفرات البرمجية المنطقية في ملفات العرض blade.</p>
[<p dir="rtl">🔝 الرجوع للفهرس</p>](#الفهرس)
================================================
FILE: bangla.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
অনুবাদঃ
[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol))
[한국어](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))
[ภาษาไทย](thai.md) (by [kongvut sangkla](https://github.com/kongvut))
[فارسی](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))
[বাংলা](bangla.md) (by [Anowar Hossain](https://github.com/AnowarCST))
[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31))
[اردو](urdu.md) (by [RizwanAshraf1](https://github.com/RizwanAshraf1))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## সূচীপত্র
[সিঙ্গেল রেস্পন্সিবিলিটি প্রিন্সিপল বা একক দায়িত্ব নীতি](#সিঙ্গেল-রেস্পন্সিবিলিটি-প্রিন্সিপল-বা-একক-দায়িত্ব-নীতি)
[ফ্যাট মডেলস, স্কীনি কন্ট্রোলারস](#ফ্যাট-মডেলস-স্কীনি-কন্ট্রোলারস)
[ভ্যালিডেশন](#ভ্যালিডেশন)
[বিসনেস লজিক সমূহ সার্ভিস ক্লাসে থাকা প্রয়োজন](#বিসনেস-লজিক-সমূহ-সার্ভিস-ক্লাসে-থাকা-প্রয়োজন)
[একি জিনিস বার বার করবেন না। (DRY)](#একি-জিনিস-বার-বার-করবেন-না-dry)
[Query Builder এবং Raw SQL Query লেখার পরিবর্তে Eloquent কে গুরুত্ব দিন। Array থেকে Collection ব্যবহার কে গুরুত্ব দিন](#query-builder-এবং-raw-sql-query-লেখার-পরিবর্তে-eloquent-কে-গুরুত্ব-দিন-array-থেকে-collection-ব্যবহার-কে-গুরুত্ব-দিন)
[সমানে এসাইন করা](#সমানে-এসাইন-করা)
[ব্লেড-টেমপ্লেটে কোয়েরী লিখবেন-না এবং একবারে লোড করুন। (N + 1 সমস্যা)](#ব্লেড-টেমপ্লেটে-কোয়েরী-লিখবেন-না-এবং-একবারে-লোড-করুন-n--1-সমস্যা)
[কোড মন্তব্য লিখতে সমস্যা নাই, কিন্তু মেথডের নামকরণ এবং ভেরিয়েবলের নামকরণ মন্তব্য থেকে বেশি গুরুত্বপুর্ণ](#কোড-মন্তব্য-লিখতে-সমস্যা-নাই-কিন্তু-মেথডের-নামকরণ-এবং-ভেরিয়েবলের-নামকরণ-মন্তব্য-থেকে-বেশি-গুরুত্বপুর্ণ)
[ব্লেড টেমপ্লেটের মধ্যে JS এবং CSS সরাসরি ইঞ্জেক্ট করবেন না এবং PHP Class এ HTML লিখবেন না](#ব্লেড-টেমপ্লেটের-মধ্যে-js-এবং-css-সরাসরি-ইঞ্জেক্ট-করবেন-না-এবং-php-class-এ-html-লিখবেন-না)
[সরাসরি লেখা থেকে কনফিগারেশন, ল্যাঙ্গুয়েজ এবং কনস্টান্ট ফাইল ব্যাবহার করুন](#সরাসরি-লেখা-থেকে-কনফিগারেশন-ল্যাঙ্গুয়েজ-এবং-কনস্টান্ট-ফাইল-ব্যাবহার-করুন)
[কমিউনিটিতে প্রচলিত মানসম্মত লারাভেলের টুলস গুলো ব্যাবহার করুন](#কমিউনিটিতে-প্রচলিত-মানসম্মত-লারাভেলের-টুলস-গুলো-ব্যাবহার-করুন)
[লারাভেল নেমিং কনভেনশন অনুসরণ করুন](#লারাভেল-নেমিং-কনভেনশন-অনুসরণ-করুন)
[যত সম্ভব সংক্ষিপ্ত ও সহজে পড়া যায় এমন সিনট্যাক্স লিখবেন](#যত-সম্ভব-সংক্ষিপ্ত-ও-সহজে-পড়া-যায়-এমন-সিনট্যাক্স-লিখবেন)
[নতুন ক্লাসের পরিবর্তে IoC কন্টেইনার বা facades ব্যবহার করুন](#নতুন-ক্লাসের-পরিবর্তে-ioc-কন্টেইনার-বা-facades-ব্যবহার-করুন)
[`.env` ফাইলের ডাটা সরাসরি নিবেন না](#env-ফাইলের-ডাটা-সরাসরি-নিবেন-না)
[তারিখ গুলো স্ট্যান্ডার্ড ফরম্যাট এ রাখবেন। তারিখের ফরম্যাট পরিবর্তনের জন্য accessors এবং mutators ব্যবহার করুন](#তারিখ-গুলো-স্ট্যান্ডার্ড-ফরম্যাট-এ-রাখবেন-তারিখের-ফরম্যাট-পরিবর্তনের-জন্য-accessors-এবং-mutators-ব্যবহার-করুন)
[অন্যান্য ভাল অনুশীলন](#অন্যান্য-ভাল-অনুশীলন)
### **সিঙ্গেল রেস্পন্সিবিলিটি প্রিন্সিপল বা একক দায়িত্ব নীতি**
একটা ক্লাস এবং একটা মেথডের একটা করে কাজ/দায়িত্ব হওয়া উচিৎ।
খারাপঃ
```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;
}
}
```
ভালঃ
```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;
}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **ফ্যাট মডেলস, স্কীনি কন্ট্রোলারস**
সবগুলো ডাটাবেস লজিক Eloquent মডেলে অথবা Repository ক্লাসে থাকা উচিৎ, আপনি যদি Query Builder অথবা raw SQL queries ব্যাবহার করেন।
খারাপঃ
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
ভালঃ
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **ভ্যালিডেশন**
ভ্যালিডেশন কোড গুলো Controller থেকে Request class এ সরিয়ে ফেলুন।
খারাপঃ
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
ভালঃ
```php
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',
];
}
}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **বিসনেস লজিক সমূহ সার্ভিস ক্লাসে থাকা প্রয়োজন**
একটা কন্ট্রোলারের একটাই কাজ হওয়া উচিৎ। তাই বিজনেস লজিক গুলো কন্ট্রোলার থেকে সার্ভিস ক্লাসে সরিয়ে ফেলুন।
খারাপঃ
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
ভালঃ
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **একি জিনিস বার বার করবেন না। (DRY)**
কোডের পুনঃব্যবহার নিশ্চিত করুন। বার বার লেখার থেকে SRP আপনাকে সাহায্য করবে। সাথে Blade টেম্পলেট, Eloquent স্কোপ ইত্যাদির পুনঃব্যবহার করুন।
খারাপঃ
```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();
}
```
ভালঃ
```php
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();
}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **Query Builder এবং Raw SQL Query লেখার পরিবর্তে Eloquent কে গুরুত্ব দিন। Array থেকে Collection ব্যবহার কে গুরুত্ব দিন**
Eloquent আপনাকে পাঠযোগ্য এবং রক্ষণাবেক্ষণযোগ্য কোড করতে সাহায্য করবে। এছাড়াও, Eloquent এর বেশ কিছু বিল্ট-ইন টুলস আছে যেমনঃ soft deletes, events, scopes ইত্যাদি।
খারাপঃ
```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
```
ভালঃ
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **সমানে এসাইন করা**
খারাপঃ
```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();
```
ভালঃ
```php
$category->article()->create($request->validated());
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **ব্লেড-টেমপ্লেটে কোয়েরী লিখবেন-না এবং একবারে লোড করুন। (N + 1 সমস্যা)**
খারাপ (১০০ জন ইউজারের জন্য, ১০১ টা DB queries এক্সিকিউট হবে):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
ভালো (১০০ জন ইউজারের জন্য, ২ টা DB queries এক্সিকিউট হবে)-ঃ
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **কোড মন্তব্য লিখতে সমস্যা নাই, কিন্তু মেথডের নামকরণ এবং ভেরিয়েবলের নামকরণ মন্তব্য থেকে বেশি গুরুত্বপুর্ণ**
খারাপঃ
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
তুলনামূলক ভালঃ
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
ভালঃ
```php
if ($this->hasJoins())
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **ব্লেড টেমপ্লেটের মধ্যে JS এবং CSS সরাসরি ইঞ্জেক্ট করবেন না এবং PHP Class এ HTML লিখবেন না**
খারাপঃ
```javascript
let article = `{{ json_encode($article) }}`;
```
তুলনামূলক ভালঃ
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
Javascript ফাইলের এর মধ্যেঃ
```javascript
let article = $('#article').val();
```
সবচেয়ে ভালো হয় আলাদা ভাবে PHP থেকে JS প্যাকেজে ডাটা ট্র্যান্সফার করা।
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **সরাসরি লেখা থেকে কনফিগারেশন, ল্যাঙ্গুয়েজ এবং কনস্টান্ট ফাইল ব্যাবহার করুন**
খারাপঃ
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
ভালঃ
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **কমিউনিটিতে প্রচলিত মানসম্মত লারাভেলের টুলস গুলো ব্যাবহার করুন**
অন্যকোন থার্ডপার্টি packages বা tools ব্যাবহার করা থেকে লারাভেলের নিজস্ব ফাংশনালিটি এবং কমিউনিটি প্যাকেজ ব্যাবহার করা ভাল। ভবিষ্যতে কোন ডেভেলপার আপনার প্রজেক্টে কাজ করতে গেলে তাকে টুলস গুলো শিখে নেয়া লাগবে। এছাড়াও, থার্ডপার্টি packages বা 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
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **লারাভেল নেমিং কনভেনশন অনুসরণ করুন**
[PSR standards](https://www.php-fig.org/psr/psr-12/) অনুসরণ করুন।
এছাড়াও, লারাভেল কমিউনিটি কর্তৃক স্বীকৃত নামকরণের রীতি(নেমিং কনভেনশন) অনুসরণ করা যায়ঃ
কি | কিভাবে | ভাল | খারাপ
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Route name | snake_case with dot notation | users.show_active | ~~users.show-active, show-active-users~~
Model | singular | User | ~~Users~~
hasOne or belongsTo relationship | singular | articleComment | ~~articleComments, article_comment~~
All other relationships | plural | articleComments | ~~articleComment, article_comments~~
Table | plural | article_comments | ~~article_comment, articleComments~~
Pivot table | singular model names in alphabetical order | article_user | ~~user_article, articles_users~~
Table column | snake_case without model name | meta_title | ~~MetaTitle; article_meta_title~~
Model property | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | singular model name with _id suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Method | camelCase | getAll | ~~get_all~~
Method in resource controller | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Method in test class | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptive, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptive, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Config and language files index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjective or noun | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjective | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **যত সম্ভব সংক্ষিপ্ত ও সহজে পড়া যায় এমন সিনট্যাক্স লিখবেন**
খারাপঃ
```php
$request->session()->get('cart');
$request->input('name');
```
ভালঃ
```php
session('cart');
$request->name;
```
আরো উদাহরণঃ
সাধারণ সিনটেক্স | সংক্ষিপ্ত এবং আরো সহজে পাঠযোগ্য সিনটেক্স
------------ | -------------
`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`
`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')`
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **নতুন ক্লাসের পরিবর্তে IoC কন্টেইনার বা facades ব্যবহার করুন**
নতুন ক্লাসের সিনট্যাক্স ক্লাস গুলোকে টাইট কাপলিং করে এবং টেস্টিং জটিল করে। এর থেকে ভালো IoC container অথবা facades ব্যাবহার করা।
খারাপঃ
```php
$user = new User;
$user->create($request->validated());
```
ভালঃ
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **`.env` ফাইলের ডাটা সরাসরি নিবেন না**
বরং ডাটা গুলোকে কনফিগ ফাইলের মধ্যে রাখুন এবং `config()` হেল্পার ফাংশন ব্যাবহার করে আপনার এপ্লিকেশনে ব্যবহার করুন।
খারাপঃ
```php
$apiKey = env('API_KEY');
```
ভালঃ
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **তারিখ গুলো স্ট্যান্ডার্ড ফরম্যাট এ রাখবেন। তারিখের ফরম্যাট পরিবর্তনের জন্য accessors এবং mutators ব্যবহার করুন**
খারাপঃ
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
ভালঃ
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
### **অন্যান্য ভাল অনুশীলন**
routes ফাইলের মধ্যে কখনো লজিক রাখবেন না।
Blade টেম্পলেটের মধ্যে ভ্যানিলা PHP এর ব্যাবহার কমায় ফেলেন।
[🔝 সূচীপত্রে ফিরে যান](#সূচীপত্র)
================================================
FILE: burmese.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app) and [Eloquent SQL reference](https://github.com/alexeymezenin/eloquent-sql-reference)
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))
[Română](romanian.md) (by [als698](https://github.com/als698))
[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))
[မြန်မာဘာသာ](burmese.md) (by [Kaung Zay Yan](https://github.com/KaungZayY))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Contents
[အလုပ်တစ်ခုပဲ တာဝန်ယူနိယာမ](#အလုပ်တစ်ခုပဲ-တာဝန်ယူနိယာမ)
[Method တစ်ခုက အလုပ်တစ်ခုပဲလုပ်သင့်ပါတယ်](#Method-တစ်ခုက-အလုပ်တစ်ခုပဲလုပ်သင့်ပါတယ်)
[Fat models, skinny controllers](#fat-models-skinny-controllers)
[Validation](#validation)
[Business logic တွေက Service class ထဲမှာပဲ ရှိသင့်တယ်](#business-logic-တွေက-Service-class-ထဲမှာပဲ-ရှိသင့်တယ်)
[ထပ်တစ်လဲလဲပြန်မရေးနဲ့ (DRY)](#ထပ်တစ်လဲလဲပြန်မရေးနဲ့-DRY)
[Query Builder နဲ့ raw SQL queries အစား Eloquent၊ arrays အစား collection ကိုပိုသုံးပါ](#query-builder-နဲ့-raw-sql-queries-အစား-eloquent-arrays-အစား-collection-ကိုပိုသုံးပါ)
[Mass assignment](#mass-assignment)
[Queries တွေကို Blade Templates တွေထဲမှာ Execute မလုပ်ပဲနဲ့ အဲတာအစား eager loading ကိုအသုံးပြုပါ။ (N + 1 problem)](#queries-တွေကို-blade-templates-တွေထဲမှာ-execute-မလုပ်ပဲနဲ့-အဲတာအစား-eager-loading-ကိုအသုံးပြုပါ-n--1-problem)
[Data-heavy tasks တွေအတွက် Chunk data ကိုသုံးပါ](#data-heavy-tasks-တွေအတွက်-chunk-data-ကိုသုံးပါ)
[Comment ရေးမဲ့ အစား method နဲ့ variable name တွေကို သေချာပေးခဲ့ပါ](#comment-ရေးမဲ့-အစား-method-နဲ့-variable-name-တွေကို-သေချာပေးခဲ့ပါ)
[JS နဲ့ CSS ကို blade templates ထဲကို မထည့်ပါနဲ့၊ PHP class တွေထဲမှာ HTML code တွေမထည့်ပါနဲ့](#js-နဲ့-css-ကို-blade-templates-ထဲကို-မထည့်ပါနဲ့-php-class-တွေထဲမှာ-html-code-တွေမထည့်ပါနဲ့)
[Code ထဲမှာ hard coded စာသားတွေ ထည့်မဲ့အစား config နဲ့ language files တွေကိုသုံးပါ](#code-ထဲမှာ-hard-coded-စာသားတွေ-ထည့်မဲ့အစား-config-နဲ့-language-files-တွေကိုသုံးပါ)
[Community က လက်ခံပြီး အသုံးပြုနေကျ standard laravel tools တွေကိုပဲသုံးပါ](#community-က-လက်ခံပြီး-အသုံးပြုနေကျ-standard-laravel-tools-တွေကိုပဲသုံးပါ)
[Laravel ရဲ့ အမည်ပေးပုံတွေကိုလိုက်နာပါ](#laravel-ရဲ့-အမည်ပေးပုံတွေကိုလိုက်နာပါ)
[Convention over configuration](#convention-over-configuration)
[တိုတိုနဲ့ ဖတ်ရလွယ်တဲ့ syntax ကိုတက်နိုင်သမျှသုံးပါ](#တိုတိုနဲ့-ဖတ်ရလွယ်တဲ့-syntax-ကိုတက်နိုင်သမျှသုံးပါ)
[new Class အစား loC / Service container တွေကိုသုံးပါ](#new-class-အစား-loC--Service-container-တွေကိုသုံးပါ)
[`.env` file ကနေ data ကိုတိုက်ရိုက်မယူပါနဲ့](#env-file-ကနေ-data-ကိုတိုက်ရိုက်မယူပါနဲ့)
[ရက်စွဲတွေကို standard format အတိုင်းသိမ်းပါ။ Date format တွေကို modify လုပ်ချင်ရင် accessors နဲ့ mutators ကိုသုံးပါ](#ရက်စွဲတွေကို-standard-format-အတိုင်းသိမ်းပါ-date-format-တွေကို-modify-လုပ်ချင်ရင်-accessors-နဲ့-mutators-ကိုသုံးပါ)
[DocBlocks တွေကိုမသုံးပါနဲ့](#docblocks-တွေကိုမသုံးပါနဲ့)
[တစ်ခြားအလေ့အကျင့်ကောင်းများ](#တစ်ခြားအလေ့အကျင့်ကောင်းများ)
### **အလုပ်တစ်ခုပဲ တာဝန်ယူနိယာမ**
Class တစ်ခုမှာ တာဝန်တစ်ခုပဲရှိသင့်ပါတယ်။
Bad:
```php
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:
```php
public function update(UpdateRequest $request): string
{
$this->logService->logEvents($request->events);
$this->event->updateGeneralEvent($request->validated());
return back();
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Method တစ်ခုက အလုပ်တစ်ခုပဲလုပ်သင့်ပါတယ်**
Function တစ်ခုက အလုပ်တစ်ခုကိုပဲ သေချာလုပ်သင့်ပါတယ်။
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;
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Fat models, skinny controllers**
DB logic တွေ အကုန်လုံးကို Eloquent Model ထဲကို ထည့်ပါ။
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();
}
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Validation**
Validation စစ်တာကို controller ထဲမှာ မစစ်ပဲ request class ထဲမှာစစ်ပါ။
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',
];
}
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Business logic တွေက Service class ထဲမှာပဲ ရှိသင့်တယ်**
Controller တစ်ခုက အလုပ်တစ်ခုပဲ လုပ်သင့်တယ်။ Business logic တွေကို သပ်သပ် service class ထဲကိုရွှေ့ပါ။
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');
}
}
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **ထပ်တစ်လဲလဲပြန်မရေးနဲ့ (DRY)**
Code ကိုတက်နိုင်သမျှ ထပ်တစ်လဲလဲပြန်မရေးပဲနဲ့ ပြန်သုံးပါ။ Blade templates၊ Eloquent scopes တွေကိုပြန်သုံးပါ။
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();
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Query Builder နဲ့ raw SQL queries အစား Eloquent၊ arrays အစား collection ကိုပိုသုံးပါ**
Eloquent က code ကို ဖတ်လို့လွယ် ပြုပြင်ဖို့လွယ်စေတယ်။ နောက်ပြီး eloquent မှာ သုံးလို့ကောင်းတဲ့ soft deletes, events, scopes စတဲ့ build-in tools တွေ ပါပါတယ်။ ဒီမှာဝင်ဖတ်ကြည့်လို့ရပါတယ် [Eloquent to SQL reference](https://github.com/alexeymezenin/eloquent-sql-reference)
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();
```
[🔝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());
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Queries တွေကို Blade Templates တွေထဲမှာ Execute မလုပ်ပဲနဲ့ အဲတာအစား eager loading ကိုအသုံးပြုပါ။ (N + 1 problem)**
Bad (user အယောက် ၁၀၀ အတွက် Query ၁၀၁ ခု execute လုပ်ရမယ် ):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Good (user အယောက် ၁၀၀ အတွက် Query ၂ ခု ပဲ execute ရမယ်):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Data-heavy tasks တွေအတွက် Chunk data ကိုသုံးပါ**
Bad:
```php
$users = $this->get();
foreach ($users as $user) {
...
}
```
Good:
```php
$this->chunk(500, function ($users) {
foreach ($users as $user) {
...
}
});
```
[🔝 Back to contents](#contents)
### **Comment ရေးမဲ့ အစား method နဲ့ variable name တွေကို သေချာပေးခဲ့ပါ**
Bad:
```php
// Determine if there are any joins
if (count((array) $builder->getQuery()->joins) > 0)
```
Good:
```php
if ($this->hasJoins())
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **JS နဲ့ CSS ကို blade templates ထဲကို မထည့်ပါနဲ့၊ PHP class တွေထဲမှာ HTML code တွေမထည့်ပါနဲ့**
Bad:
```javascript
let article = `{{ json_encode($article) }}`;
```
Better:
```php
<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:
```javascript
let article = $('#article').val();
```
အကောင်းဆုံးကတော့ data transfer ဖို့အတွက် specialized PHP to JS Package တွေကိုသုံးပါ။
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Code ထဲမှာ hard coded စာသားတွေ ထည့်မဲ့အစား config နဲ့ language files တွေကိုသုံးပါ**
Bad:
```php
public function isNormal(): bool
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Good:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Community က လက်ခံပြီး အသုံးပြုနေကျ standard laravel tools တွေကိုပဲသုံးပါ**
3rd party packages နဲ့ tools တွေ သုံးမဲ့အစား build-in laravel functionality တွေနဲ့ community packages တွေကိုသာ ပိုသုံးသင့်ပါတယ်။ မဟုတ်ရင် နောက်ပိုင်းမှာ ကိုယ့် project ကို တစ်ခြား developer တွေ ဆက်ပြီး လုပ်တဲ့အခါမှာ tools အသစ်တွေကိုထပ်ပြီး လေ့လာနေရပါလိမ့်မယ်။ ဒါ့အပြင် တစ်ခြား third party package နဲ့ tool သုံးခဲ့ရင် အဲဒီ tools တွေနဲ့ ပက်သတ်ပြီး community ဆီကနေ အကူအညီရနိုင်ခြေလဲ သိသိသာသာလျော့သွားပါလိမ့်မယ်။ ကိုယ့် client ကို အဲတာအတွက် အပိုမကုန်ပါစေနဲ့။
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
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Laravel ရဲ့ အမည်ပေးပုံတွေကိုလိုက်နာပါ**
Follow [PSR standards](https://www.php-fig.org/psr/psr-12/).
နောက်ပြီး laravel community က လက်ခံထားတဲ့ အမည်ပေးပုံတွေကိုလိုက်နာပါ။
What | How | Good | Bad
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Route name | snake_case with dot notation | users.show_active | ~~users.show-active, show-active-users~~
Model | singular | User | ~~Users~~
hasOne or belongsTo relationship | singular | articleComment | ~~articleComments, article_comment~~
All other relationships | plural | articleComments | ~~articleComment, article_comments~~
Table | plural | article_comments | ~~article_comment, articleComments~~
Pivot table | singular model names in alphabetical order | article_user | ~~user_article, articles_users~~
Table column | snake_case without model name | meta_title | ~~MetaTitle; article_meta_title~~
Model property | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | singular model name with _id suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Method | camelCase | getAll | ~~get_all~~
Method in resource controller | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Method in test class | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptive, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptive, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Config and language files index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjective or noun | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjective | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **Convention over configuration**
တစ်ချို့ naming conventions တွေကိုလိုက်နာနေရင် တစ်ခြား configuration တွေလုပ်စရာမလိုတော့ဘူး။
Bad:
```php
// 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:
```php
// Table name 'customers'
// Primary key 'id'
class Customer extends Model
{
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **တိုတိုနဲ့ ဖတ်ရလွယ်တဲ့ syntax ကိုတက်နိုင်သမျှသုံးပါ**
Bad:
```php
$request->session()->get('cart');
$request->input('name');
```
Good:
```php
session('cart');
$request->name;
```
နောက်ထပ် ဥပမာများ:
တွေ့မြင်နေကျ syntax | တိုတိုနဲ့ ဖတ်ရလွယ် 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')`
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **new Class အစား loC / Service container တွေကိုသုံးပါ**
new Class syntax က class တွေအတွင်းမှာ tight coupling ဖြစ်စေတဲ့အပြင် testing လုပ်တဲ့အခါမှာ ပိုပြီး ရှုတ်ထွေးစေတယ်။ အဲ့အစား LoC container နဲ့ facades ကိုသုံးပါ။
Bad:
```php
$user = new User;
$user->create($request->validated());
```
Good:
```php
public function __construct(protected User $user) {}
...
$this->user->create($request->validated());
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **`.env` file ကနေ data ကိုတိုက်ရိုက်မယူပါနဲ့**
အဲလိုလုပ်မဲ့အစား application မှာသုံးရမဲ့ data ကို config files တွေဆီပို့ပြီးတော့ `config()` helper function ကိုသုံးပါ။
Bad:
```php
$apiKey = env('API_KEY');
```
Good:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **ရက်စွဲတွေကို standard format အတိုင်းသိမ်းပါ။ Date format တွေကို modify လုပ်ချင်ရင် accessors နဲ့ mutators ကိုသုံးပါ**
ရက်စွဲတစ်ခုကို စာသား(string) အနေနဲ့သိမ်းတာက object instance အနေနဲ့သိမ်းတာလောက် စိတ်မချရဘူး ၊ ဥပမာ Carbon-instance။ Class အချင်းချင်းကြား date string အနေနဲ့ ပေးတာထက် carbon objects အနေနဲ့ပေးတာကို ပိုအားပေးပါတယ်။ ဒေတာပြန်ပြတာကိုတော့ display layer(templates) မှာပဲ လုပ်သင့်ပါတယ်။
Bad:
```php
{{ 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:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
// Blade view
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->format('m-d') }}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **DocBlocks တွေကိုမသုံးပါနဲ့**
DocBlocks တွေက ဖတ်ရတာ ပိုခက်စေတယ်။ အဲ့အစား method name ကိုသေချာပေးတာ နဲ့ အသစ်ထွက် PHP feautre တွေဖြစ်တဲ့ return type hints တွေကိုသုံးပါ။
Bad:
```php
/**
* 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:
```php
public function isValidAsciiString(string $string): bool
{
}
```
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
### **တစ်ခြားအလေ့အကျင့်ကောင်းများ**
Laravel၊ တစ်ခြား ဆင်တူတဲ့(RoR၊ Django)အစရှိတဲ့ frameworks တွေနဲ့စိမ်းတဲ့ patterns တွေ tools တွေကိုမသုံးပါနဲ့။ App တစ်ခုဆောက်ဖို့ကို Symfony (ဒါမှမဟုတ် Spring) ရဲ့ approach ကို သုံးရတာကြိုက်ရင် အဲဒီ framework ကိုပဲသုံးလိုက်သင့်ပါတယ်။
Route file တွေမှာ ဘာlogic မှမထည့်ပါနဲ့။
Vanilla PHP ကို Blade templates တွေမှာ နည်းနိုင်သမျှ နည်းသုံးပါ။
Testing အတွက် in-memory DB ကိုသုံးပါ။
Framework version update လုပ်တာ နဲ့ တစ်ခြား issues တွေမတက်အောင် framework ရဲ့ standard features တွေကိုပြင်မရေးပါနဲ့။
နောက်ထွက် PHP syntax တွေကိုတက်နိုင်သမျှ အသုံးပြုပါ ဒါပေမယ့် ဖတ်ရလွယ်အောင်ရေးဖို့လဲ မမေ့ပါနဲ့။
တကယ်သေချာမသိရင် View Composers နဲ့ တစ်ခြားဆင်တူတဲ့ tools တွေကိုမသုံးပါနဲ့။ များသောအားဖြင့် ပြဿနာကို ဖြေရှင်းဖို့ ပိုကောင်းတဲ့ နည်းတွေရှိပါတယ်။
[🔝Contents တွေဆီပြန်သွားမယ်](#contents)
================================================
FILE: chinese.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
多国语言列表:
[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol))
[한국어](https://github.com/xotrs/laravel-best-practices) (by [cherrypick](https://github.com/xotrs))
[Українська](ukrainian.md) (by [Tenevyk](https://github.com/tenevyk))
[Русский](russian.md)
[فارسی](persian.md) (by [amirhossein baghaie](https://github.com/ohmydevops))
[Português](https://github.com/jonaselan/laravel-best-practices) (by [jonaselan](https://github.com/jonaselan))
[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))
[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31))
[اردو](urdu.md) (by [RizwanAshraf1](https://github.com/RizwanAshraf1))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## 内容
[单一职责原则](#单一职责原则)
[保持控制器的简洁](#保持控制器的简洁)
[使用自定义Request类来进行验证](#使用自定义Request类来进行验证)
[业务代码要放到服务层中](#业务代码要放到服务层中)
[DRY原则 不要重复自己](#DRY原则-不要重复自己)
[使用ORM而不是纯sql语句,使用集合而不是数组](#使用ORM而不是纯sql语句使用集合而不是数组)
[集中处理数据](#集中处理数据)
[不要在模板中查询,尽量使用惰性加载](#不要在模板中查询尽量使用惰性加载)
[注释你的代码,但是更优雅的做法是使用描述性的语言来编写你的代码](#注释你的代码但是更优雅的做法是使用描述性的语言来编写你的代码)
[不要把 JS 和 CSS 放到 Blade 模板中,也不要把任何 HTML 代码放到 PHP 代码里](#不要把-JS-和-CSS-放到-Blade-模板中也不要把任何-HTML-代码放到-PHP-代码里)
[在代码中使用配置、语言包和常量,而不是使用硬编码](#在代码中使用配置语言包和常量而不是使用硬编码)
[使用社区认可的标准Laravel工具](#使用社区认可的标准Laravel工具)
[遵循laravel命名约定](#遵循laravel命名约定)
[尽可能使用简短且可读性更好的语法](#尽可能使用简短且可读性更好的语法)
[使用IOC容器来创建实例 而不是直接new一个实例](#使用IOC容器来创建实例-而不是直接new一个实例)
[避免直接从 `.env` 文件里获取数据](#避免直接从-env-文件里获取数据)
[使用标准格式来存储日期,用访问器和修改器来修改日期格式](#使用标准格式来存储日期用访问器和修改器来修改日期格式)
[其他的好建议](#其他的一些好建议)
### **单一职责原则**
一个类和一个方法应该只有一个责任。
例如:
```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;
}
}
```
更优的写法:
```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;
}
```
[🔝 返回目录](#内容)
### **保持控制器的简洁**
如果您使用的是查询生成器或原始SQL查询,请将所有与数据库相关的逻辑放入Eloquent模型或Repository类中。
例如:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
更优的写法:
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 返回目录](#内容)
### **使用自定义Request类来进行验证**
把验证规则放到 Request 类中.
例子:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
更优的写法:
```php
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',
];
}
}
```
[🔝 返回目录](#内容)
### **业务代码要放到服务层中**
控制器必须遵循单一职责原则,因此最好将业务代码从控制器移动到服务层中。
例子:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
更优的写法:
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 返回目录](#内容)
### **DRY原则 不要重复自己**
尽可能重用代码,SRP可以帮助您避免重复造轮子。 此外尽量重复使用Blade模板,使用Eloquent的 scopes 方法来实现代码。
例子:
```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();
}
```
更优的写法:
```php
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();
}
```
[🔝 返回目录](#内容)
### **使用ORM而不是纯sql语句,使用集合而不是数组**
使用Eloquent可以帮您编写可读和可维护的代码。 此外Eloquent还有非常优雅的内置工具,如软删除,事件,范围等。
例子:
```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
```
更优的写法:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 返回目录](#内容)
### **集中处理数据**
例子:
```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();
```
更优的写法:
```php
$category->article()->create($request->validated());
```
[🔝 返回目录](#内容)
### **不要在模板中查询,尽量使用惰性加载**
例子 (对于100个用户,将执行101次DB查询):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
更优的写法 (对于100个用户,使用以下写法只需执行2次DB查询):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 返回目录](#内容)
### **注释你的代码,但是更优雅的做法是使用描述性的语言来编写你的代码**
例子:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
加上注释:
```php
// 确定是否有任何连接
if (count((array) $builder->getQuery()->joins) > 0)
```
更优的写法:
```php
if ($this->hasJoins())
```
[🔝 返回目录](#内容)
### **不要把 JS 和 CSS 放到 Blade 模板中,也不要把任何 HTML 代码放到 PHP 代码里**
例子:
```javascript
let article = `{{ json_encode($article) }}`;
```
更好的写法:
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
在Javascript文件中加上:
```javascript
let article = $('#article').val();
```
当然最好的办法还是使用专业的PHP的JS包传输数据。
[🔝 返回目录](#内容)
### **在代码中使用配置、语言包和常量,而不是使用硬编码**
例子:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
更优的写法:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 返回目录](#内容)
### **使用社区认可的标准Laravel工具**
强力推荐使用内置的Laravel功能和扩展包,而不是使用第三方的扩展包和工具。
如果你的项目被其他开发人员接手了,他们将不得不重新学习这些第三方工具的使用教程。
此外,当您使用第三方扩展包或工具时,你很难从Laravel社区获得什么帮助。 不要让你的客户为额外的问题付钱。
想要实现的功能 | 标准工具 | 第三方工具
------------ | ------------- | -------------
权限 | Policies | Entrust, Sentinel 或者其他扩展包
资源编译工具| Laravel Mix, Vite | Grunt, Gulp, 或者其他第三方包
开发环境| Laravel Sail, Homestead | Docker
部署 | Laravel Forge | Deployer 或者其他解决方案
自动化测试 | PHPUnit, Mockery | Phpspec, Pest
页面预览测试 | Laravel Dusk | Codeception
DB操纵 | Eloquent | SQL, Doctrine
模板 | Blade | Twig
数据操纵 | Laravel集合 | 数组
表单验证| Request classes | 他第三方包,甚至在控制器中做验证
权限 | Built-in | 他第三方包或者你自己解决
API身份验证 | Laravel Passport, Laravel Sanctum | 第三方的JWT或者 OAuth 扩展包
创建 API | Built-in | Dingo API 或者类似的扩展包
创建数据库结构 | Migrations | 直接用 DB 语句创建
本土化 | Built-in |第三方包
实时消息队列 | Laravel Echo, Pusher | 使用第三方包或者直接使用WebSockets
创建测试数据| Seeder classes, Model Factories, Faker | 手动创建测试数据
任务调度| Laravel Task Scheduler | 脚本和第三方包
数据库 | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB
[🔝 返回目录](#内容)
### **遵循laravel命名约定**
来源 [PSR standards](https://www.php-fig.org/psr/psr-12/).
另外,遵循Laravel社区认可的命名约定:
对象 | 规则 | 更优的写法 | 应避免的写法
------------ | ------------- | ------------- | -------------
控制器 | 单数 | ArticleController | ~~ArticlesController~~
路由 | 复数 | articles/1 | ~~article/1~~
路由命名| 带点符号的蛇形命名 | users.show_active | ~~users.show-active, show-active-users~~
模型 | 单数 | User | ~~Users~~
hasOne或belongsTo关系 | 单数 | articleComment | ~~articleComments, article_comment~~
所有其他关系 | 复数 | articleComments | ~~articleComment, article_comments~~
表单 | 复数 | article_comments | ~~article_comment, articleComments~~
透视表| 按字母顺序排列模型 | article_user | ~~user_article, articles_users~~
数据表字段| 使用蛇形并且不要带表名 | meta_title | ~~MetaTitle; article_meta_title~~
模型参数 | 蛇形命名 | $model->created_at | ~~$model->createdAt~~
外键 | 带有_id后缀的单数模型名称 | article_id | ~~ArticleId, id_article, articles_id~~
主键 | - | id | ~~custom_id~~
迁移 | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
方法 | 驼峰命名 | getAll | ~~get_all~~
资源控制器 | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
测试类| 驼峰命名 | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
变量 | 驼峰命名 | $articlesWithAuthor | ~~$articles_with_author~~
集合 | 描述性的, 复数的 | $activeUsers = User::active()->get() | ~~$active, $data~~
对象 | 描述性的, 单数的 | $activeUser = User::active()->first() | ~~$users, $obj~~
配置和语言文件索引 | 蛇形命名 | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
视图 | 短横线命名 | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
配置 | 蛇形命名 | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
内容 (interface) | 形容词或名词 | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | 使用形容词 | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 返回目录](#内容)
### **尽可能使用简短且可读性更好的语法**
例子:
```php
$request->session()->get('cart');
$request->input('name');
```
更优的写法:
```php
session('cart');
$request->name;
```
更多示例:
常规写法 | 更优雅的写法
------------ | -------------
`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`
`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')`
[🔝 返回目录](#内容)
### **使用IOC容器来创建实例 而不是直接new一个实例**
创建新的类会让类之间的更加耦合,使得测试越发复杂。请改用IoC容器或注入来实现。
例子:
```php
$user = new User;
$user->create($request->validated());
```
更优的写法:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 返回目录](#内容)
### **避免直接从 `.env` 文件里获取数据**
将数据传递给配置文件,然后使用`config()`帮助函数来调用数据
例子:
```php
$apiKey = env('API_KEY');
```
更优的写法:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝 返回目录](#内容)
### **使用标准格式来存储日期,用访问器和修改器来修改日期格式**
例子:
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
更优的写法:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[🔝 返回目录](#内容)
### **其他的一些好建议**
永远不要在路由文件中放任何的逻辑代码。
尽量不要在Blade模板中写原始 PHP 代码。
[🔝 返回目录](#内容)
================================================
FILE: french.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
Traductions:
[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol))
[한국어](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))
[ภาษาไทย](thai.md) (by [kongvut sangkla](https://github.com/kongvut))
[فارسی](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))
[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31))
[اردو](urdu.md) (by [RizwanAshraf1](https://github.com/RizwanAshraf1))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Contenu
[Principe de responsabilité unique](#principe-de-responsabilité-unique)
[Gros Modèles, contrôleurs maigres](#gros-modèles-contrôleurs-maigres)
[Validation](#validation)
[La logique métier doit être dans une classe de service](#la-logique-métier-doit-être-dans-une-classe-de-service)
[Ne te répète pas (DRY)](#ne-te-répète-pas-dry)
[Préférez utiliser Eloquent à l’utilisation de Query Builder et de requêtes SQL brutes. Préférez les collections aux tableaux](#préférez-utiliser-eloquent-à-lutilisation-de-query-builder-et-de-requêtes-sql-brutes-préférez-les-collections-aux-tableaux)
[Affectation en masse](#affectation-en-masse)
[N'exécutez pas de requêtes dans les modèles de blade et utilisez un chargement rapide (N + 1 problème)](#nexécutez-pas-de-requêtes-dans-les-modèles-blade-et-utilisez-un-chargement-rapide-eager-loading-problème-n--1)
[Commentez votre code, mais préférez une méthode descriptive et les noms de variables aux commentaires](#commentez-votre-code-mais-préférez-une-méthode-descriptive-et-des-noms-de-variables-aux-commentaires)
[Ne mettez pas JS et CSS dans les templates Blade et ne mettez pas de HTML dans les classes PHP](#ne-mettez-pas-js-et-css-dans-les-templates-blade-et-ne-mettez-pas-de-html-dans-les-classes-php)
[Utilisez des fichiers de configuration et de langue, des constantes au lieu du texte dans le code](#utilisez-des-fichiers-de-configuration-et-de-langue-des-constantes-au-lieu-du-texte-dans-le-code)
[Utiliser les outils standard de Laravel acceptés par la communauté](#utiliser-les-outils-standard-de-laravel-acceptés-par-la-communauté)
[Suivre les conventions de nommage de Laravel](#suivre-les-conventions-de-nommage-de-laravel)
[Utilisez une syntaxe plus courte et plus lisible dans la mesure du possible](#utilisez-une-syntaxe-plus-courte-et-plus-lisible-dans-la-mesure-du-possible)
[Utilisez un conteneur IoC ou des façades au lieu de la nouvelle classe](#utilisez-un-conteneur-ioc-ou-des-façades-au-lieu-de-la-nouvelle-classe)
[Ne pas obtenir directement les données du fichier `.env` directement](#ne-pas-obtenir-directement-les-données-du-fichier-env)
[Stocker les dates au format standard. Utiliser des accesseurs et des mutateurs pour modifier le format de date](#stocker-les-dates-au-format-standard-Utiliser-des-accesseurs-et-des-mutateurs-pour-modifier-le-format-de-date)
[D'autres bonnes pratiques](#dautres-bonnes-pratiques)
### **Principe de responsabilité unique**
Une classe et une méthode ne devraient avoir qu'une seule responsabilité.
Mal:
```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;
}
}
```
Bien:
```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;
}
```
[🔝 Retour au contenu](#contents)
### **Gros modèles, contrôleurs maigres**
Placez toute la logique liée à la base de données dans les modèles Eloquent ou dans les classes du Repository si vous utilisez le générateur de requêtes ou des requêtes SQL brutes.
Mal:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
Bien:
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 Retour au contenu](#contents)
### **Validation**
Déplacez la validation des contrôleurs vers les classes Request.
Mal:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
Bien:
```php
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',
];
}
}
```
[🔝 Retour au contenu](#contents)
### **La logique métier doit être dans une classe de service**
Un contrôleur ne doit avoir qu'une seule responsabilité. Par conséquent, déplacez la logique métier des contrôleurs vers les classes de service.
Mal:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
Bien:
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 Retour au contenu](#contents)
### **Ne te répète pas (DRY)**
Réutilisez le code quand vous le pouvez. SRP vous aide à éviter les doubles emplois. Réutilisez également les modèles Blade, utilisez les Eloquent scopes, etc.
Mal:
```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();
}
```
Bien:
```php
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();
}
```
[🔝 Retour au contenu](#contents)
### **Préférez utiliser Eloquent à l’utilisation de Query Builder et de requêtes SQL brutes. Préférez les collections aux tableaux**
Eloquent vous permet d’écrire du code lisible et maintenable. Eloquent dispose également d'excellents outils intégrés tels que les suppressions, les événements, les scopes, etc.
Mal:
```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
```
Bien:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 Retour au contenu](#contents)
### **Affectation en masse**
Mal:
```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();
```
Bien:
```php
$category->article()->create($request->validated());
```
[🔝 Retour au contenu](#contents)
### **N'exécutez pas de requêtes dans les modèles Blade et utilisez un chargement rapide (eager loading) (problème N + 1)**
Mal (Pour 100 utilisateurs, 101 requêtes DB seront exécutées):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Bien (pour 100 utilisateurs, 2 requêtes de base de données seront exécutées):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 Retour au contenu](#contents)
### **Commentez votre code, mais préférez une méthode descriptive et des noms de variables aux commentaires**
Mal:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
Meilleure:
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
Bien:
```php
if ($this->hasJoins())
```
[🔝 Retour au contenu](#contents)
### **Ne mettez pas JS et CSS dans les templates Blade et ne mettez pas de HTML dans les classes PHP**
Mal:
```javascript
let article = `{{ json_encode($article) }}`;
```
Meilleure:
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
Dans un fichier Javascript:
```javascript
let article = $('#article').val();
```
Le meilleur moyen consiste à utiliser un package PHP vers JS spécialisé pour transférer les données.
[🔝 Retour au contenu](#contents)
### **Utilisez des fichiers de configuration et de langue, des constantes au lieu du texte dans le code**
Mal:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Bien:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 Retour au contenu](#contents)
### **Utiliser les outils standard de Laravel acceptés par la communauté**
Préférez utiliser les fonctionnalités intégrées de Laravel et les packages de communauté au lieu d'utiliser des packages et des outils tiers. Tout développeur qui travaillera avec votre application à l'avenir devra apprendre de nouveaux outils. En outre, les chances d'obtenir de l'aide de la communauté Laravel sont considérablement réduites lorsque vous utilisez un package ou un outil tiers. Ne faites pas payer votre client pour cela.
Tâche | Outils standard | Outils tiers
------------ | ------------- | -------------
Autorisation | Policies | Entrust, Sentinel et d'autres packages
Compiler des assets | Laravel Mix, Vite | Grunt, Gulp, packages tiers
Environnement de développement | Laravel Sail, Homestead | Docker
Déploiement | Laravel Forge | Deployer et d'autre solutions
Tests unitaires | PHPUnit, Mockery | Phpspec, Pest
Test du navigateur | Laravel Dusk | Codeception
DB | Eloquent | SQL, Doctrine
Templates | Blade | Twig
Travailler avec des données | Laravel collections | Arrays
Validation du formulaire | Request classes | 3rd party packages, validation dans le contrôleur
Authentification | Built-in | 3rd party packages, votre propre solution
API D'authentification | Laravel Passport, Laravel Sanctum | 3rd party JWT et OAuth packages
Création d'API | Built-in | Dingo API and similar packages
Travailler avec une structure de base de données | Migrations | Travailler directement avec la structure de la base de données
Localisation | Built-in | 3rd party packages
Interfaces utilisateur en temps réel | Laravel Echo, Pusher | Packages tiers et utilisation directe de WebSockets
Générer des données de test | Seeder classes, Model Factories, Faker | Création manuelle de données de test
Planification des tâches | Laravel Task Scheduler | Scripts et packages tiers
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB
[🔝 Retour au contenu](#contents)
### **Suivre les conventions de nommage de Laravel**
Suivre [Normes PSR](https://www.php-fig.org/psr/psr-12/).
Suivez également les conventions de nommage acceptées par la communauté Laravel:
Quoi | Comment | Bien | Mal
------------ | ------------- | ------------- | -------------
Controller | singulier | ArticleController | ~~ArticlesController~~
Route | pluriel | articles/1 | ~~article/1~~
Route nommée | snake_case avec notation par points | users.show_active | ~~users.show-active, show-active-users~~
Model | singulier | User | ~~Users~~
Relations hasOne or belongsTo | singulier | articleComment | ~~articleComments, article_comment~~
Toutes les autres relations | pluriel | articleComments | ~~articleComment, article_comments~~
Table | plurielle | article_comments | ~~article_comment, articleComments~~
Table pivot | noms des modèles au singulier dans l'ordre alphabétique | article_user | ~~user_article, articles_users~~
Colonne de table | snake_case sans nom de modèle | meta_title | ~~MetaTitle; article_meta_title~~
Attribut du Model | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | Nom du modèle au singulier avec _id comme suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Méthode | camelCase | getAll | ~~get_all~~
Méthodes dans le controlleur de ressource | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Méthode dans une classe de test | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptif, pluriel | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptif, singulier | $activeUser = User::active()->first() | ~~$users, $obj~~
Index de fichier de config et de langage | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
Vue | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjectif ou nom | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjectif | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 Retour au contenu](#contents)
### **Utilisez une syntaxe plus courte et plus lisible dans la mesure du possible**
Mal:
```php
$request->session()->get('cart');
$request->input('name');
```
Bien:
```php
session('cart');
$request->name;
```
Plus d'exemples:
Syntaxe commune | Syntaxe plus courte et plus lisible
------------ | -------------
`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`
`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')`
[🔝 Retour au contenu](#contents)
### **Utilisez un conteneur IoC ou des façades au lieu de la nouvelle classe**
La nouvelle syntaxe de classe crée un couplage étroit entre les classes et complique les tests. Utilisez plutôt le conteneur IoC ou les façades.
Mal:
```php
$user = new User;
$user->create($request->validated());
```
Bien:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 Retour au contenu](#contents)
### **Ne pas obtenir directement les données du fichier `.env`**
Passez les données aux fichiers de configuration à la place, puis utilisez la fonction d'assistance `config ()` pour utiliser les données dans une application.
Mal:
```php
$apiKey = env('API_KEY');
```
Bien:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝 Retour au contenu](#contents)
### **Stocker les dates au format standard. Utiliser des accesseurs et des mutateurs pour modifier le format de date**
Mal:
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
Bien:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[🔝 Retour au contenu](#contents)
### **D'autres bonnes pratiques**
Ne mettez jamais aucune logique dans les fichiers de routes.
Minimisez l'utilisation de PHP vanilla dans les modèles de blade.
[🔝 Retour au contenu](#contents)
================================================
FILE: german.md
================================================

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))
[한국어](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))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Inhaltsverzeichnis
[Single-Responsibility-Prinzip](#single-responsibility-prinzip)
[Fette Models, schlanke Controller](#fette-models-schlanke-controller)
[Validierung](#validierung)
[Geschäftslogik sollte in einer Serviceklasse sein](#geschäftslogik-sollte-in-einer-serviceklasse-sein)
[Wiederholen Sie sich nicht / Don't repeat yourself (DRY)](#wiederholen-sie-sich-nicht--dont-repeat-yourself-dry)
[Verwenden Sie Eloquent anstelle des Query Builders und rohen SQL-Abfragen. Bevorzugen Sie Collections gegenüber Arrays](#verwenden-sie-lieber-eloquent-anstelle-des-query-builders-und-rohen-sql-abfragen-bevorzugen-sie-collections-gegenüber-arrays)
[Massenzuordnung](#massenzuordnung)
[Führen Sie keine Abfragen in Blade-Templates aus und verwenden Sie eager loading (N + 1-Problem)](#führen-sie-keine-abfragen-in-blade-templates-aus-und-verwenden-sie-eager-loading-n--1-problem)
[Kommentieren Sie Ihren Code, aber bevorzugen Sie beschreibende Methoden- und Variablennamen gegenüber Kommentaren](#kommentieren-sie-ihren-code-aber-bevorzugen-sie-beschreibende-methoden--und-variablennamen-gegenüber-kommentaren)
[Schreiben Sie kein JS und CSS in Blade-Templates und schreiben Sie kein HTML in PHP-Klassen](#schreiben-sie-kein-js-und-css-in-blade-templates-und-schreiben-sie-kein-html-in-php-klassen)
[Verwenden Sie Konfigurations- und Sprachdateien und Konstanten anstelle von Text im Code](#verwenden-sie-konfigurations--und-sprachdateien-und-konstanten-anstelle-von-text-im-code)
[Verwenden Sie Standard-Laravel-Tools, die von der Community akzeptiert werden](#verwenden-sie-standard-laravel-tools-die-von-der-community-akzeptiert-werden)
[Befolgen Sie die Namenskonventionen von Laravel](#befolgen-sie-die-namenskonventionen-von-laravel)
[Verwenden Sie nach Möglichkeit eine kürzere und besser lesbare Syntax](#verwenden-sie-nach-möglichkeit-eine-kürzere-und-besser-lesbare-syntax)
[Verwenden Sie IoC-Container oder Facades, statt neue Klassen zu instanziieren](#verwenden-sie-ioc-container-oder-facades-statt-neue-klassen-zu-instanziieren)
[Rufen Sie Daten nicht direkt aus der `.env`-Datei ab](#rufen-sie-daten-nicht-direkt-aus-der-env-datei-ab)
[Speichern Sie Datumsangaben im Standardformat. Verwenden Sie Accessoren und Mutatoren, um das Datumsformat zu ändern](#speichern-sie-datumsangaben-im-standardformat-verwenden-sie-accessoren-und-mutatoren-um-das-datumsformat-zu-ändern)
[Andere gute Praktiken](#andere-gute-praktiken)
### **Single-Responsibility-Prinzip**
Eine Klasse und eine Methode sollten nur eine Verantwortung haben.
Schlecht:
```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;
}
}
```
Gut:
```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;
}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Fette Models, schlanke Controller**
Fügen Sie die gesamte DB-bezogene Logik in Eloquent-Models oder in Repository-Klassen ein, wenn Sie Query Builder oder SQL-Rohabfragen verwenden.
Schlecht:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
Gut:
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Validierung**
Verschieben Sie die Validierung von Controllern in Request-Klassen.
Schlecht:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
Gut:
```php
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',
];
}
}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Geschäftslogik sollte in einer Serviceklasse sein**
Ein Controller darf nur eine Verantwortung haben, also verschieben Sie die Geschäftslogik von Controllern in Serviceklassen.
Schlecht:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
Gut:
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Wiederholen Sie sich nicht / Don't repeat yourself (DRY)**
Verwenden Sie Code wieder, wenn Sie können. Das Single-Responsibility-Prinzip (SRP) hilft Doppelarbeit zu vermeiden. Verwenden Sie auch Blade Templates, Eloquent Scopes etc. wieder.
Schlecht:
```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();
}
```
Gut:
```php
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();
}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Verwenden Sie lieber Eloquent anstelle des Query Builders und rohen SQL-Abfragen. Bevorzugen Sie Collections gegenüber Arrays**
Eloquent ermöglicht es, lesbaren und wartbaren Code schreiben. Außerdem verfügt Eloquent über großartige integrierte Tools wie Soft Deletes, Events, Scopes usw.
Schlecht:
```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
```
Gut:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Massenzuordnung**
Schlecht:
```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();
```
Gut:
```php
$category->article()->create($request->validated());
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Führen Sie keine Abfragen in Blade-Templates aus und verwenden Sie eager loading (N + 1-Problem)**
Schlecht (für 100 Benutzer werden 101 Datenbankabfragen ausgeführt):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Gut (für 100 Benutzer werden 2 Datenbankabfragen ausgeführt):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Kommentieren Sie Ihren Code, aber bevorzugen Sie beschreibende Methoden- und Variablennamen gegenüber Kommentaren**
Schlecht:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
Besser:
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
Gut:
```php
if ($this->hasJoins())
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Schreiben Sie kein JS und CSS in Blade-Templates und schreiben Sie kein HTML in PHP-Klassen**
Schlecht:
```javascript
let article = `{{ json_encode($article) }}`;
```
Besser:
```php
<input id="article" type="hidden" value='@json($article)'>
oder
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
In einer JavaScript-Datei:
```javascript
let article = $('#article').val();
```
Am besten verwenden Sie ein spezielles PHP-zu-JS-Paket, um die Daten zu übertragen.
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Verwenden Sie Konfigurations- und Sprachdateien und Konstanten anstelle von Text im Code**
Schlecht:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Gut:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Verwenden Sie Standard-Laravel-Tools, die von der Community akzeptiert werden**
Verwenden Sie vorzugsweise integrierte Laravel-Funktionen und Community-Pakete, anstatt Pakete und Tools von Drittanbietern zu verwenden. Ansonsten muss jeder Entwickler, der in Zukunft an Ihrer App arbeitet, neue Tools erlernen. Außerdem sind die Chancen, Hilfe von der Laravel-Community zu erhalten, erheblich geringer, wenn Sie ein Paket oder Tool eines Drittanbieters verwenden. Lassen Sie Ihren Kunden nicht dafür bezahlen.
Aufgabe | Standardwerkzeuge | Tools von Drittanbietern
------------ | ------------- | -------------
Autorisierung | Policies | Entrust, Sentinel und andere Pakete
Assets kompilieren | Laravel Mix, Vite | Grunt, Gulp, 3rd-Party-Pakete
Entwicklungsumgebung | Laravel Sail, Homestead | Docker
Bereitstellung | Laravel Forge | Deployer und andere Lösungen
Unit Tests | PHPUnit, Mockery | Phpspec, Pest
Browsertests | Laravel Dusk | Codeception
DB | Eloquent | SQL, Doctrine
Templates | Blade | Twig
Mit Daten arbeiten | Laravel Collections | Arrays
Formularvalidierung | Request-Klassen | Pakete von Drittanbietern, Validierung im Controller
Authentifizierung | Integriert | Pakete von Drittanbietern, Ihre eigene Lösung
API-Authentifizierung | Laravel Passport, Laravel Sanctum | JWT- und OAuth-Pakete von Drittanbietern
API erstellen | Integriert | Dingo API und ähnliche Pakete
Mit DB-Struktur arbeiten | Migrationen | Direkt mit der DB-Struktur arbeiten
Lokalisierung | Integriert | Pakete von Drittanbietern
Echtzeit-Benutzeroberflächen | Laravel Echo, Pusher | Pakete von Drittanbietern und direktes Arbeiten mit WebSockets
Testdaten generieren | Seeder-Klassen, Model Factories, Faker | Testdaten manuell erstellen
Aufgabenplanung | Laravel Task Scheduler | Skripte und Pakete von Drittanbietern
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Befolgen Sie die Namenskonventionen von Laravel**
Folgen Sie den [PSR standards](https://www.php-fig.org/psr/psr-12/).
Befolgen Sie außerdem die von der Laravel-Community akzeptierten Namenskonventionen:
Was | Wie | Gut | Schlecht
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Benannte Route | snake_case mit Punktnotation | users.show_active |~~users.show-active, show-active-users~~
Model | singular | User |~~Users~~
hasOne oder belongsTo Beziehung | singular | articleComment | ~~articleComments, article_comment~~
Alle anderen Beziehungen | plural | articleComments | ~~articleComment, article_comments~~
Tabelle | Plural | article_comments |~~article_comment, articleComments~~
Pivot-Tabelle | singuläre Modellnamen in alphabetischer Reihenfolge | article_user | ~~user_article, articles_users~~
Tabellenspalte | snake_case ohne Modellname | meta_title | ~~MetaTitle; article_title_title~~
Model-Eigenschaft | snake_case | $model->created_at | ~~$model->createdAt~~
Fremdschlüssel | singulärer Modellname mit Suffix _id | article_id | ~~ArticleId, id_article, articles_id~~
Primärschlüssel | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Methode | camelCase | getAll | ~~get_all~~
Methode im Ressourcencontroller | [Tabelle](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Methode in einer Testklasse | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | beschreibend, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Objekt | beschreibend, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Konfigurations- und Sprachdateien index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Vertrag (Interface) | Adjektiv oder Substantiv | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | Adjektiv | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Verwenden Sie nach Möglichkeit eine kürzere und besser lesbare Syntax**
Schlecht:
```php
$request->session()->get('cart');
$request->input('name');
```
Gut:
```php
session('cart');
$request->name;
```
Mehr Beispiele:
Gängige Syntax | Kürzere und lesbarere 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`
`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')`
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Verwenden Sie IoC-Container oder Facades, statt neue Klassen zu instanziieren**
Die Syntax `new Class` erzeugt eine enge Kopplung zwischen Klassen und erschwert dadurch das Testen. Verwenden Sie stattdessen IoC-Container oder Facades.
Schlecht:
```php
$user = new User;
$user->create($request->validated());
```
Gut:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Rufen Sie Daten nicht direkt aus der `.env`-Datei ab**
Übergeben Sie die Daten stattdessen an eine Konfigurationsdatei und verwenden Sie dann die Hilfsfunktion `config()`, um die Daten in ihrer Anwendung zu verwenden.
Schlecht:
```php
$apiKey = env('API_KEY');
```
Gut:
```php
// config/api.php
'key' => env('API_KEY'),
// Verwendung der Daten
$apiKey = config('api.key');
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Speichern Sie Datumsangaben im Standardformat. Verwenden Sie Accessoren und Mutatoren, um das Datumsformat zu ändern**
Strings für Daten sind generell weniger belastbar als Objekte (z.B. Carbon Objekte). Es ist empfehlenswert Carbon-Instanzen zwischen Klassen zu übergeben. Formatierung sollte in den blade Dateien erfolgen:
Schlecht:
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
Gut:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
// Blade view
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->format('m-d') }}
```
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
### **Andere gute Praktiken**
Logik sollte nicht in Routes Dateien eingebaut werden.
Minimieren Sie die Verwendung von Vanilla PHP in Blade-Templates.
[🔝 Zurück zum Inhaltsverzeichnis](#inhaltsverzeichnis)
================================================
FILE: indonesia.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Konten
[Prinsip *single responsibility*](#prinsip-single-responsibility)
[Model tebal, *controller* tipis](#model-tebal-controller-tipis)
[Validasi](#validasi)
[*Business logic* harus di dalam kelas *services*](#business-logic-harus-di-dalam-kelas-services)
[*Don't repeat yourself* (DRY)](#dont-repeat-yourself-dry)
[Lebih memilih menggunakan *Eloquent* daripada menggunakan *Query Builder* dan query SQL mentah. Lebih memilih *collections* daripada *array*](#lebih-memilih-menggunakan-eloquent-daripada-menggunakan-query-builder-dan-query-sql-mentah-lebih-memilih-collections-daripada-array)
[*Mass assignment*](#mass-assignment)
[Jangan mengeksekusi kueri dalam *template blade* dan gunakan *eager loading* (masalah N + 1)](#jangan-mengeksekusi-kueri-dalam-template-blade-dan-gunakan-eager-loading-masalah-n-1)
[Komentari kode anda, tetapi lebih baik *method* dan nama variabel yang deskriptif daripada komentar](#komentari-kode-anda-tetapi-lebih-baik-method-dan-nama-variabel-yang-deskriptif-daripada-komentar)
[Jangan letakkan JS dan CSS di *template blade* dan jangan letakkan HTML apa pun di kelas PHP](#jangan-letakkan-js-dan-css-di-template-blade-dan-jangan-letakkan-html-apa-pun-di-kelas-php)
[Gunakan file *config*, *language*, dan konstanta daripada teks dalam kode](#gunakan-file-config-language-dan-konstanta-daripada-teks-dalam-kode)
[Gunakan *tools* standar Laravel yang diterima oleh komunitas](#gunakan-tools-standar-laravel-yang-diterima-oleh-komunitas)
[Ikuti konvensi penamaan Laravel](#ikuti-konvensi-penamaan-laravel)
[Gunakan sintaks yang lebih pendek dan lebih mudah dibaca jika memungkinkan](#gunakan-sintaks-yang-lebih-pendek-dan-lebih-mudah-dibaca-jika-memungkinkan)
[Gunakan *IoC Container* atau *facades* daripada kelas baru](#gunakan-ioc-container-atau-facades-daripada-kelas-baru)
[Jangan mendapatkan data dari file `.env` secara langsung](#jangan-mendapatkan-data-dari-file-env-secara-langsung)
[Simpan tanggal dalam format standar. Gunakan *accessors* dan *mutators* untuk mengubah format tanggal](#simpan-tanggal-dalam-format-standar-gunakan-accessors-dan-mutators-untuk-mengubah-format-tanggal)
[Praktik bagus lainnya](#praktik-bagus-lainnya)
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
### **Prinsip *single responsibility***
Kelas dan metode seharusnya hanya memiliki satu tanggung jawab.
Contoh buruk:
```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;
}
}
```
Contoh terbaik:
```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;
}
```
[🔝 Kembali ke konten](#konten)
### **Model tebal, *controller* tipis**
Masukkan semua logika terkait DB ke model *eloquent* atau ke dalam kelas repositori jika anda menggunakan *Query Builder* atau kueri SQL mentah.
Contoh buruk:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
Contoh terbaik:
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 Kembali ke konten](#konten)
### **Validasi**
Pindahkan validasi dari *controller* ke kelas *request*.
Contoh buruk:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
Contoh terbaik:
```php
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',
];
}
}
```
[🔝 Kembali ke konten](#konten)
### ***Business logic* harus di dalam kelas *services***
*Controller* harus hanya memiliki satu tanggung jawab, jadi pindahkan *business logic* dari *controller* ke kelas *service*.
Contoh buruk:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
Contoh terbaik:
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 Kembali ke konten](#konten)
### ***Don't repeat yourself* (DRY)**
Gunakan kembali kode ketika anda bisa. [PSR](#prinsip-single-responsibility) membantu anda menghindari duplikasi. Juga, gunakan kembali *template blade*, *scope eloquent*, dll.
Contoh buruk:
```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();
}
```
Contoh terbaik:
```php
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();
}
```
[🔝 Kembali ke konten](#konten)
### **Lebih memilih menggunakan *Eloquent* daripada menggunakan *Query Builder* dan query SQL mentah. Lebih memilih *collections* daripada *array***
*Eloquent* memungkinkan anda menulis kode yang dapat dibaca dan *maintainable*. Dan, *Eloquent* memiliki *built-in tools* yang bagus seperti *soft deletes*, *events*, *scopes*, dll.
Contoh buruk:
```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
```
Contoh terbaik:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 Kembali ke konten](#konten)
### ***Mass assignment***
Contoh buruk:
```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();
```
Contoh terbaik:
```php
$category->article()->create($request->validated());
```
[🔝 Kembali ke konten](#konten)
### **Jangan mengeksekusi kueri dalam *template blade* dan gunakan *eager loading* (masalah N + 1)**
Contoh buruk (untuk 100 *user*, 101 kueri DB akan dieksekusi):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Contoh terbaik (untuk 100 *user*, 2 kueri DB akan dieksekusi):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 Kembali ke konten](#konten)
### **Komentari kode anda, tetapi lebih baik *method* dan nama variabel yang deskriptif daripada komentar**
Contoh buruk:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
Contoh lebih baik:
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
Contoh terbaik:
```php
if ($this->hasJoins())
```
[🔝 Kembali ke konten](#konten)
### **Jangan letakkan JS dan CSS di *template blade* dan jangan letakkan HTML apa pun di kelas PHP**
Contoh buruk:
```javascript
let article = `{{ json_encode($article) }}`;
```
Contoh lebih baik:
```php
<input id="article" type="hidden" value='@json($article)'>
Atau
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
Dalam file javascript:
```javascript
let article = $('#article').val();
```
Cara terbaik adalah dengan menggunakan *package* `PHP to JS` khusus untuk mentransfer data.
[🔝 Kembali ke konten](#konten)
### **Gunakan file *config*, *language*, dan konstanta daripada teks dalam kode**
Contoh buruk:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Contoh terbaik:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 Kembali ke konten](#konten)
### **Gunakan *tools* standar Laravel yang diterima oleh komunitas**
Selalu gunakan fungsi *built-in* bawaan laravel dan *packages* komunitas daripada menggunakan *packages* dan *tools* pihak ke-3. *Developer* manapun yang akan bekerja dengan aplikasi anda di masa mendatang perlu mempelajari *tools* baru. Dan juga, peluang untuk mendapatkan bantuan dari komunitas Laravel jauh lebih rendah saat anda menggunakan *packages* atau *tools* pihak ke-3. Jangan membuat klien Anda membayar untuk itu.
Task | Tools *standar* | *Tools* pihak ke-3
------------ | ------------- | -------------
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
[🔝 Kembali ke konten](#konten)
### **Ikuti konvensi penamaan Laravel**
Ikuti [PSR standards](https://www.php-fig.org/psr/psr-12/).
Dan juga, ikuti konvensi penamaan yang diterima oleh komunitas Laravel:
What | How | Good | Bad
------------ | ------------- | ------------- | -------------
Controller | singular | ArticleController | ~~ArticlesController~~
Route | plural | articles/1 | ~~article/1~~
Route name | snake_case with dot notation | users.show_active | ~~users.show-active, show-active-users~~
Model | singular | User | ~~Users~~
hasOne or belongsTo relationship | singular | articleComment | ~~articleComments, article_comment~~
All other relationships | plural | articleComments | ~~articleComment, article_comments~~
Table | plural | article_comments | ~~article_comment, articleComments~~
Pivot table | singular model names in alphabetical order | article_user | ~~user_article, articles_users~~
Table column | snake_case without model name | meta_title | ~~MetaTitle; article_meta_title~~
Model property | snake_case | $model->created_at | ~~$model->createdAt~~
Foreign key | singular model name with _id suffix | article_id | ~~ArticleId, id_article, articles_id~~
Primary key | - | id | ~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
Method | camelCase | getAll | ~~get_all~~
Method in resource controller | [table](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Method in test class | camelCase | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
Variable | camelCase | $articlesWithAuthor | ~~$articles_with_author~~
Collection | descriptive, plural | $activeUsers = User::active()->get() | ~~$active, $data~~
Object | descriptive, singular | $activeUser = User::active()->first() | ~~$users, $obj~~
Config and language files index | snake_case | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
Contract (interface) | adjective or noun | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | adjective | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 Kembali ke konten](#konten)
### **Gunakan sintaks yang lebih pendek dan lebih mudah dibaca jika memungkinkan**
Contoh buruk:
```php
$request->session()->get('cart');
$request->input('name');
```
Contoh terbaik:
```php
session('cart');
$request->name;
```
Contoh:
Sintaks umum | Sintaks pendek dan mudah dibaca
------------ | -------------
`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`
`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')`
[🔝 Kembali ke konten](#konten)
### **Gunakan *IoC Container* atau *facades* daripada kelas baru**
Sintaks Kelas baru membuat penggabungan yang sempit antar kelas dan memperumit proses pengujian. Gunakan *facades* atau *IoC container* sebagai gantinya.
Contoh buruk:
```php
$user = new User;
$user->create($request->validated());
```
Contoh terbaik:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 Kembali ke konten](#konten)
### **Jangan mendapatkan data dari file `.env` secara langsung**
Alihkan data ke file konfigurasi sebagai gantinya dan kemudian gunakan fungsi `config ()` untuk menggunakan data dalam aplikasi.
Contoh buruk:
```php
$apiKey = env('API_KEY');
```
Contoh terbaik:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[🔝 Kembali ke konten](#konten)
### **Simpan tanggal dalam format standar. Gunakan *accessors* dan *mutators* untuk mengubah format tanggal**
Contoh buruk:
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
Contoh terbaik:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[🔝 Kembali ke konten](#konten)
### **Praktik bagus lainnya**
Jangan pernah menaruh logika apa pun di file `route`.
Minimalkan penggunaan *vanilla* PHP di *template blade*.
[🔝 Kembali ke konten](#konten)
================================================
FILE: italian.md
================================================

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))
[한국어](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))
[ภาษาไทย](thai.md) (by [kongvut sangkla](https://github.com/kongvut))
[فارسی](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))
[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31))
[اردو](urdu.md) (by [RizwanAshraf1](https://github.com/RizwanAshraf1))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## Contenuto
[Principio della sola responsabilità](#single-responsibility-principle)
[Modelli grassi, controller skinny](#fat-models-skinny-controllers)
[Validazione](#validation)
[La logica aziendale dovrebbe essere nella classe di servizio](#business-logic-should-be-in-service-class)
[Non ripeterti (SECCO)](#dont-repeat-yourself-dry)
[Preferisco usare Eloquent rispetto a Query Builder e query SQL non elaborate. Preferisce raccolte su array](#prefer-to-use-eloquent-over-using-query-builder-and-raw-sql-queries-prefer-collections-over-arrays)
[Assegnazione di massa](#mass-assignment)
[Non eseguire query nei modelli Blade e utilizzare il caricamento desideroso (problema N + 1)](#do-not-execute-queries-in-blade-templates-and-use-eager-loading-n--1-problem)
[Commenta il tuo codice, ma preferisci il metodo descrittivo e i nomi delle variabili rispetto ai commenti](#comment-your-code-but-prefer-descriptive-method-and-variable-names-over-comments)
[Non inserire JS e CSS nei modelli Blade e non inserire HTML nelle classi PHP](#do-not-put-js-and-css-in-blade-templates-and-do-not-put-any-html-in-php-classes)
[Usa file di configurazione e lingua, costanti anziché testo nel codice](#use-config-and-language-files-constants-instead-of-text-in-the-code)
[Utilizzare gli strumenti standard Laravel accettati dalla community](#use-standard-laravel-tools-accepted-by-community)
[Segui le convenzioni di denominazione di Laravel](#follow-laravel-naming-conventions)
[Utilizzare la sintassi più breve e più leggibile ove possibile](#use-shorter-and-more-readable-syntax-where-possible)
[Utilizzare il contenitore o le facciate IoC anziché la nuova classe](#use-ioc-container-or-facades-instead-of-new-class)
[Non ottiene direttamente i dati dal file `.env`](#do-not-get-data-from-the-env-file-directly)
[Memorizza le date nel formato standard. Utilizzare accessori e mutatori per modificare il formato della data](#store-dates-in-the-standard-format-use-accessors-and-mutators-to-modify-date-format)
[Altre buone pratiche](#other-good-practices)
### **Principio di singola responsabilità**
Una classe e un metodo dovrebbero avere una sola responsabilità.
Sbagliato:
```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;
}
}
```
Giusto:
```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;
}
```
[🔝Torna ai contenuti](#contents)
### **Fat models, skinny controllers**
Inserisci tutta la logica legata al DB nei Model Eloquent oppure nei Repository a seconda che tu stia usando il Query Builder o le query SQL raw.
Sbagliato:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
Giusto:
```php
public function index()
{
return view('index', ['clients' => $this->client->getWithNewOrders()]);
}
class Client extends Model
{
public function getWithNewOrders()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[Torna ai contenuti](#contents)
### **Validazione**
Sposta le logiche di validazione dai controller alle Request class.
Sbagliato:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
Giusto:
```php
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',
];
}
}
```
[Torna ai contenuti](#contents)
### **La logica di business dovrebbe essere nella classe di servizio**
Un controller deve avere una sola responsabilità, quindi sposta la logica di business dai controller alle classi di servizio.
Sbagliato:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
Giusto:
```php
public function store(Request $request)
{
$this->articleService->handleUploadedImage($request->file('image'));
...
}
class ArticleService
{
public function handleUploadedImage($image)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[Torna ai contenuti](#contents)
### **Non ripeterti (DRY: Don't Repeat Yourself)**
Riutilizzare il codice quando è possibile. Il Principio di Singola Responsabilità (SRP) ti aiuta a evitare la duplicazione. Inoltre, riutilizza i template blade, usa gli eloquenti scopes, ecc.
Sbagliato:
```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();
}
```
Giusto:
```php
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();
}
```
[Torna ai contenuti](#contents)
### **Favorisci l'utilizzo dei Model Eloquent rispetto al Query Builder e alle query SQL raw. Preferisci le Collection agli array**
Eloquent ti consente di scrivere codice leggibile e manutenibile. Inoltre, Eloquent ha ottimi strumenti integrati come eliminazioni soft, eventi, scopes, ecc.
Sbagliato:
```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
```
Giusto:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[Torna ai contenuti](#contents)
### **Assegnazione di massa**
Sbagliato:
```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();
```
Giusto:
```php
$category->article()->create($request->validated());
```
[Torna ai contenuti](#contents)
### **Non eseguire query nei template Blade e utilizzare l'eager loading (problema N + 1)**
Sbagliato (per 100 utenti, verranno eseguite 101 query DB):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Giusto (per 100 utenti, verranno eseguite 2 query DB):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[Torna ai contenuti](#contents)
### **Commenta il tuo codice, ma cerca anche di rendere autoesplicativi i nomi di metodi e variabili**
Sbagliato:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
Meglio:
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
Giusto:
```php
if ($this->hasJoins())
```
[Torna ai contenuti](#contents)
### **Non inserire JS e CSS nei templte Blade e non inserire HTML nelle classi PHP**
Sbagliato:
```javascript
let article = `{{ json_encode($article) }}`;
```
Meglio:
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
In un file Javascript:
```javascript
let article = $('#article').val();
```
Il modo migliore è utilizzare il pacchetto PHP-JS specializzato per trasferire i dati.
[Torna ai contenuti](#contents)
### **Usa file di configurazione e lingua, costanti anziché testo nel codice**
Sbagliato:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Giusto:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[Torna ai contenuti](#contents)
### **Utilizzare gli strumenti standard Laravel accettati dalla community**
Favorisci l'utilizzo delle funzionalità integrate in Laravel e i pacchetti della community anziché utilizzare pacchetti e strumenti di terze parti. Altrimenti, qualsiasi sviluppatore che lavorerà con la tua app in futuro dovrà imparare nuovi strumenti. Inoltre, le possibilità di ottenere aiuto dalla comunità Laravel sono significativamente inferiori quando si utilizza un pacchetto o uno strumento di terze parti. Non far pagare il tuo cliente per quello.
Task | Strumenti standard | Strumenti di terze parti
------------ | ------------- | -------------
Autorizzazione | Policies | Entrust, Sentinel e altri pacchetti
Compiling assets | Laravel Mix, Vite | Grunt, Gulp, pacchetti terzi
Ambiente di sviluppo | Laravel Sail, Homestead | Docker
Distribuzione | Laravel Forge | Deployer e altre soluzioni
Test unitari | PHPUnit, Mockery | Phpspec, Pest
Test dal browser | Laravel Dusk | Codeception
DB | Eloquent, Query Builder | SQL, Doctrine
Template | Blade | Twig
Lavorare con i dati | Laravel collection | Array
Validazione form | Form Request | Pacchetti di terze parti, convalida nel controller
Autenticazione | Incorporato | Pacchetti di terze parti, la tua soluzione
Autenticazione API | Laravel Passport, Laravel Sanctum | Pacchetti JWT e OAuth di terze parti
Creazione dell'API | Incorporato | API Dingo e pacchetti simili
Lavorare con la struttura DB | Migrazioni | Lavorare direttamente con la struttura DB
Localizzazione | Incorporato | Pacchetti di terze parti
Interfacce utente in tempo reale | Laravel Echo, Pusher | Pacchetti di terze parti e funzionamento diretto con WebSocket
Generazione di dati di test | Seeder, Model Factories, Faker | Creazione manuale dei dati di test
Pianificazione delle attività | Laravel Task Scheduler | Script e pacchetti di terze parti
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB
[Torna ai contenuti](#contents)
### **Segui le naming convention di Laravel**
Seguire [Standard PSR](https://www.php-fig.org/psr/psr-12/).
Inoltre, segui le convenzioni di denominazione accettate dalla comunità Laravel:
Cosa | Come | Giusto | Sbagliato
------------ | ------------- | ------------- | -------------
Controller | singolare | ArticleController |~~ArticlesController~~
Route | plurale | articles/1 | ~~article/1~~
Route name | snake_case con notazione punto | users.show_active | ~~users.show-active, show-active-users~~
Model | singolare | User | ~~Users~~
Relazioni hasOne o belongsTo | singolare | articleComment |~~articleComments, article_comment~~
Tutte le altre relazioni | plurale | articleComments | ~~articleComment, article_comments~~
Tabella | plurale | article_comments | ~~article_comment, articleComments~~
Tabella pivot | nomi di modelli singolari in ordine alfabetico | article_user | ~~user_article, articles_users~~
Colonna della tabella | snake_case senza nome modello | meta_title |~~Meta Title; articolo meta_title~~
Proprietà del Model | snake_case | $ model->created_at |~~$model->createdAt~~
Foreign key | modello in singolare con un suffisso _id | article_id | ~~ArticleId, id_article, articles_id~~
Chiave primaria | - | id |~~custom_id~~
Migration | - | 2017_01_01_000000_create_articles_table |~~2017_01_01_000000_articles~~
Metodo | camelCase | getAll | ~~get_all~~
Metodo nel resource controller | [resource](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
Metodo nella test class | camelCase | testGuestCannotSeeArticle |~~test_guest_cannot_see_article~~
Variabile | camelCase | $articolesWithAuthor |~~$articles_with_author~~
Collection | descrittivo, plurale | $activeUsers = User::active()->get() | ~~$active, $data~~
Oggetto | descrittivo, singolare | $activeUser = User::active()->first() | ~~$users, $obj~~
Indice file di configurazione e lingua | snake_case | articles_enabled |~~ArticlesEnabled; articles-enabled~~
View | kebab-case | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
Config | snake_case | google_calendar.php |~~googleCalendar.php, google-calendar.php~~
Contratto (interfaccia) | aggettivo o sostantivo | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | aggettivo | Notificabile | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[Torna ai contenuti](#contents)
### **Utilizzare una sintassi più breve e più leggibile ove possibile**
Sbagliato:
```php
$request->session()->get('cart');
$request->input('name');
```
Giusto:
```php
session('cart');
$request->name;
```
Più esempi:
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`
`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')`
[Torna ai contenuti](#contents)
### **Utilizzare il container IoC o i Facades invece di istanziare nuove classi**
La sintassi new Class crea un accoppiamento stretto tra le classi e complica i test. Utilizzare invece il container IoC o i Facades.
Sbagliato:
```php
$user = new User;
$user->create($request->validated());
```
Giusto:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[Torna ai contenuti](#contents)
### **Non prelevare direttamente i dati dal file `.env`**
Passa i dati presenti nell'.env file ai file di configurazione e quindi usa l'helper `config ()` per prelevare i dati all'interno dell'applicazione.
Sbagliato:
```php
$apiKey = env('API_KEY');
```
Giusto:
```php
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
```
[Torna ai contenuti](#contents)
### **Memorizza le date nel formato standard. Utilizza gli accessors e i mutators per modificare il formato della data**
Sbagliato:
```php
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}
```
Giusto:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[Torna ai contenuti](#contents)
### **Altre buone pratiche**
Non inserire mai alcuna logica nei file di route.
Ridurre al minimo l'utilizzo di vanilla PHP nei template Blade.
[Torna ai contenuti](#contents)
================================================
FILE: japanese.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app)
翻訳:
[Nederlands](https://github.com/Protoqol/Beste-Laravel-Praktijken) (by [Protoqol](https://github.com/Protoqol))
[한국어](https://github.com/xotrs/laravel-best-practices) (by [cherrypick](https://github.com/xotrs))
[Українська](ukrainian.md) (by [Tenevyk](https://github.com/tenevyk))
[Русский](russian.md)
[فارسی](persian.md) (by [amirhossein baghaie](https://github.com/ohmydevops))
[Português](https://github.com/jonaselan/laravel-best-practices) (by [jonaselan](https://github.com/jonaselan))
[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))
[العربية](arabic.md) (by [ahmedsaoud31](https://github.com/ahmedsaoud31))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## コンテンツ
[単一責任の原則](#単一責任の原則)
[ファットモデル、スキニーコントローラ](#ファットモデルスキニーコントローラ)
[バリデーション](#バリデーション)
[ビジネスロジックはサービスクラスの中に書く](#ビジネスロジックはサービスクラスの中に書く)
[繰り返し書かない (DRY)](#繰り返し書かない-dry)
[クエリビルダや生のSQLクエリよりもEloquentを優先して使い、配列よりもコレクションを優先する](#クエリビルダや生のsqlクエリよりもeloquentを優先して使い配列よりもコレクションを優先する)
[マスアサインメント](#マスアサインメント)
[Bladeテンプレート内でクエリを実行しない。Eager Lodingを使う(N + 1問題)](#bladeテンプレート内でクエリを実行しないeager-lodingを使うn--1問題)
[コメントを書く。ただしコメントよりも説明的なメソッド名と変数名を付けるほうが良い](#コメントを書くただしコメントよりも説明的なメソッド名と変数名を付けるほうが良い)
[JSとCSSをBladeテンプレートの中に入れない、PHPクラスの中にHTMLを入れない](#jsとcssをbladeテンプレートの中に入れないphpクラスの中にhtmlを入れない)
[コード内の文字列の代わりにconfigファイルとlanguageのファイル、定数を使う](#コード内の文字列の代わりにconfigファイルとlanguageのファイル定数を使う)
[コミュニティに受け入れられた標準のLaravelツールを使う](#コミュニティに受け入れられた標準のLaravelツールを使う)
[Laravelの命名規則に従う](#Laravelの命名規則に従う)
[できるだけ短く読みやすい構文で書く](#できるだけ短く読みやすい構文で書く)
[newの代わりにIoCコンテナもしくはファサードを使う](#newの代わりにIoCコンテナもしくはファサードを使う)
[`.env`ファイルのデータを直接参照しない](#envファイルのデータを直接参照しない)
[日付を標準フォーマットで保存する。アクセサとミューテータを使って日付フォーマットを変更する](#日付を標準フォーマットで保存するアクセサとミューテータを使って日付フォーマットを変更する)
[その他 グッドプラクティス](#その他-グッドプラクティス)
### **単一責任の原則**
クラスとメソッドは1つの責任だけを持つべきです。
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;
}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **ファットモデル、スキニーコントローラ**
DBに関連するすべてのロジックはEloquentモデルに入れるか、もしクエリビルダもしくは生のSQLクエリを使用する場合はレポジトリークラスに入れます。
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()
{
return $this->verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
}
}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **バリデーション**
バリデーションはコントローラからリクエストクラスに移動させます。
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()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
];
}
}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **ビジネスロジックはサービスクラスの中に書く**
コントローラはただ1つの責任だけを持たないといけません、そのためビジネスロジックはコントローラからサービスクラスに移動させます。
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)
{
if (!is_null($image)) {
$image->move(public_path('images') . 'temp');
}
}
}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **繰り返し書かない (DRY)**
可能であればコードを再利用します。単一責任の原則は重複を避けることに役立ちます。また、Bladeテンプレートを再利用したり、Eloquentのスコープなどを使用したりします。
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', 1)->whereNotNull('deleted_at');
}
public function getActive()
{
return $this->active()->get();
}
public function getArticles()
{
return $this->whereHas('user', function ($q) {
$q->active();
})->get();
}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **クエリビルダや生のSQLクエリよりもEloquentを優先して使い、配列よりもコレクションを優先する**
Eloquentにより読みやすくメンテナンスしやすいコードを書くことができます。また、Eloquentには論理削除、イベント、スコープなどの優れた組み込みツールがあります。
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();
```
[🔝 コンテンツに戻る](#コンテンツ)
### **マスアサインメント**
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());
```
[🔝 コンテンツに戻る](#コンテンツ)
### **Bladeテンプレート内でクエリを実行しない。Eager Lodingを使う(N + 1問題)**
Bad (100ユーザに対して、101回のDBクエリが実行される):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
Good (100ユーザに対して、2回のDBクエリが実行される):
```php
$users = User::with('profile')->get();
@foreach ($users as $user)
{{ $user->profile->name }}
@endforeach
```
[🔝 コンテンツに戻る](#コンテンツ)
### **コメントを書く。ただしコメントよりも説明的なメソッド名と変数名を付けるほうが良い**
Bad:
```php
if (count((array) $builder->getQuery()->joins) > 0)
```
Better:
```php
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
```
Good:
```php
if ($this->hasJoins())
```
[🔝 コンテンツに戻る](#コンテンツ)
### **JSとCSSをBladeテンプレートの中に入れない、PHPクラスの中にHTMLを入れない**
Bad:
```javascript
let article = `{{ json_encode($article) }}`;
```
Better:
```php
<input id="article" type="hidden" value='@json($article)'>
Or
<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>
```
JavaScript ファイルで以下のように記述します:
```javascript
let article = $('#article').val();
```
もっとも良い方法は、データを転送するためJSパッケージに特別なPHPを使用することです。
[🔝 コンテンツに戻る](#コンテンツ)
### **コード内の文字列の代わりにconfigファイルとlanguageのファイル、定数を使う**
Bad:
```php
public function isNormal()
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
```
Good:
```php
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
```
[🔝 コンテンツに戻る](#コンテンツ)
### **コミュニティに受け入れられた標準のLaravelツールを使う**
サードパーティ製のパッケージやツールの代わりに、Laravel標準機能とコミュニティパッケージを使うことを推奨します。将来あなたと共に働くことになるどの開発者も新しいツールを学習する必要があります。また、サードパーティ製のパッケージやツールを使用している場合は、Laravelコミュニティから助けを得る機会が大幅に少なくなります。あなたのクライアントにその代金を払わせないでください。
タスク | 標準ツール | サードパーティ製ツール
------------ | ------------- | -------------
認可 | Policies | Entrust, Sentinel または他のパッケージ
アセットコンパイル | Laravel Mix, Vite | Grunt, Gulp, サードパーティ製パッケージ
開発環境 | Laravel Sail, Homestead | Docker
デプロイ | Laravel Forge | Deployer またはその他ソリューション
単体テスト| PHPUnit, Mockery | Phpspec, Pest
ブラウザテスト | Laravel Dusk | Codeception
DB | Eloquent | SQL, Doctrine
テンプレート | Blade | Twig
データの取り扱い | Laravel collections | Arrays
フォームバリデーション | Request classes | サードパーティ製パッケージ、コントローラ内でバリデーション
認証 | 標準組み込み | サードパーティ製パッケージ、独自実装
API 認証 | Laravel Passport, Laravel Sanctum | サードパーティ製の JWT や OAuth パッケージ
API作成 | 標準組み込み | Dingo API や類似パッケージ
DB構造の取り扱い | Migrations | 直接DB構造を扱う
ローカライゼーション | 標準組み込み | サードパーティ製パッケージ
リアルタイムユーザインターフェース | Laravel Echo, Pusher | サードパーティ製パッケージ または直接Webソケットを扱う
テストデータ生成 | Seeder classes, Model Factories, Faker | 手動でテストデータを作成
タスクスケジューリング | Laravel Task Scheduler | スクリプトやサードパーティ製パッケージ
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB
[🔝 コンテンツに戻る](#コンテンツ)
### **Laravelの命名規則に従う**
[PSR](https://www.php-fig.org/psr/psr-12/)に従います。
また、Laravelコミュニティに受け入れられた命名規則に従います。
対象 | 規則 | Good | Bad
------------ | ------------- | ------------- | -------------
コントローラ | 単数形 | ArticleController | ~~ArticlesController~~
ルート | 複数形 | articles/1 | ~~article/1~~
名前付きルート | スネークケースとドット表記 | users.show_active | ~~users.show-active, show-active-users~~
モデル | 単数形 | User | ~~Users~~
hasOne または belongsTo 関係 | 単数形 | articleComment | ~~articleComments, article_comment~~
その他すべての関係 | 複数形 | articleComments | ~~articleComment, article_comments~~
テーブル | 複数形 | article_comments | ~~article_comment, articleComments~~
Pivotテーブル | 単数形 モデル名のアルファベット順 | article_user | ~~user_article, articles_users~~
テーブルカラム | スネークケース モデル名は含めない | meta_title | ~~MetaTitle; article_meta_title~~
モデルプロパティ | スネークケース | $model->created_at | ~~$model->createdAt~~
外部キー | 単数形 モデル名の最後に_idをつける | article_id | ~~ArticleId, id_article, articles_id~~
主キー | - | id | ~~custom_id~~
マイグレーション | - | 2017_01_01_000000_create_articles_table | ~~2017_01_01_000000_articles~~
メソッド | キャメルケース | getAll | ~~get_all~~
リソースコントローラのメソッド | [一覧](https://laravel.com/docs/master/controllers#resource-controllers) | store | ~~saveArticle~~
テストクラスのメソッド | キャメルケース | testGuestCannotSeeArticle | ~~test_guest_cannot_see_article~~
変数 | キャメルケース | $articlesWithAuthor | ~~$articles_with_author~~
コレクション | 説明的、 複数形 | $activeUsers = User::active()->get() | ~~$active, $data~~
オブジェクト | 説明的, 単数形 | $activeUser = User::active()->first() | ~~$users, $obj~~
設定ファイルと言語ファイルのインデックス | スネークケース | articles_enabled | ~~ArticlesEnabled; articles-enabled~~
ビュー | ケバブケース | show-filtered.blade.php | ~~showFiltered.blade.php, show_filtered.blade.php~~
コンフィグ | スネークケース | google_calendar.php | ~~googleCalendar.php, google-calendar.php~~
契約 (インターフェイス) | 形容詞または名詞 | AuthenticationInterface | ~~Authenticatable, IAuthentication~~
Trait | 形容詞 | Notifiable | ~~NotificationTrait~~
Trait [(PSR)](https://www.php-fig.org/bylaws/psr-naming-conventions/) | adjective | NotifiableTrait | ~~Notification~~
Enum | singular | UserType | ~~UserTypes~~, ~~UserTypeEnum~~
FormRequest | singular | UpdateUserRequest | ~~UpdateUserFormRequest~~, ~~UserFormRequest~~, ~~UserRequest~~
Seeder | singular | UserSeeder | ~~UsersSeeder~~
[🔝 コンテンツに戻る](#コンテンツ)
### **できるだけ短く読みやすい構文で書く**
Bad:
```php
$request->session()->get('cart');
$request->input('name');
```
Good:
```php
session('cart');
$request->name;
```
さらなる例:
一般的な構文 | 短く読みやすい構文
------------ | -------------
`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`
`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')`
[🔝 コンテンツに戻る](#コンテンツ)
### **newの代わりにIoCコンテナもしくはファサードを使う**
new構文はクラス間の密結合を生み出し、テストすることを難しくします。IoCコンテナまたはファサードを代わりに使います。
Bad:
```php
$user = new User;
$user->create($request->validated());
```
Good:
```php
public function __construct(User $user)
{
$this->user = $user;
}
...
$this->user->create($request->validated());
```
[🔝 コンテンツに戻る](#コンテンツ)
### **`.env`ファイルのデータを直接参照しない**
代わりにconfigファイルへデータを渡します。そして、アプリケーション内でデータを参照する場合は`config()`ヘルパー関数を使います。
Bad:
```php
$apiKey = env('API_KEY');
```
Good:
```php
// config/api.php
'key' => env('API_KEY'),
// データを使用する
$apiKey = config('api.key');
```
[🔝 コンテンツに戻る](#コンテンツ)
### **日付を標準フォーマットで保存する。アクセサとミューテータを使って日付フォーマットを変更する**
Bad:
```php
{{ 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:
```php
// Model
protected $casts = [
'ordered_at' => 'datetime',
];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// View
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
```
[🔝 コンテンツに戻る](#コンテンツ)
### **その他 グッドプラクティス**
ルートファイルにはロジックを入れないでください。
Bladeテンプレートの中でVanilla PHP(標準のPHPコードを記述すること)の使用は最小限にします。
[🔝 コンテンツに戻る](#コンテンツ)
================================================
FILE: pashto.md
================================================

You might also want to check out the [real-world Laravel example application](https://github.com/alexeymezenin/laravel-realworld-example-app) and [Eloquent SQL reference](https://github.com/alexeymezenin/eloquent-sql-reference)
ژباړې:
[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))
[Română](romanian.md) (by [als698](https://github.com/als698))
[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))
[](https://github.com/alexeymezenin/laravel-realworld-example-app)
## د منځپانګو یا مطالبو نوملړ
[د یوه مسؤلیت اصل](#د-یوه-مسؤلیت-اصل)
[میتودونه باید یوازې یو کار ترسره کړي](#میتودونه-باید-یوازې-یو-کار-ترسره-کړي)
[لوی ماډلونه، کوچني کنټرولرونه!](#لوی-ماډلونه-کوچني-کنټرولرونه)
[ډېټا تصدیق یا اعتبار](#ډېټا-تصدیق-یا-اعتبار)
[د پروګرام منطق باید په service class کې وي.](#د-پروګرام-منطق-باید-په-service-class-کې-وي)
[د DRY اصل یا خپل ځان مه تکراروه!](#د-dry-اصل-یا-خپل-ځان-مه-تکراروه)
[د Query Builder او raw SQL queries پر ځای باید د Eloquent ORM څخه کار واخیستل شي. او همچنان د Arrays پر ځای د Collections څخه کار واخیستل شي.](#د-query-builder-او-raw-sql-queries-پر-ځای-باید-د-eloquent-orm-څخه-کار-واخیستل-شي-او-همچنان-د-arrays-پر-ځای-د-collections-څخه-کار-واخیستل-شي)
[(Mass assignment) ډله ایزه دنده](#mass-assignment-ډله-ایزه-دنده)
[د دې پر ځای چې query په blade کې ولیکئ د eager loading څخه کار واخلئ. (N+1 مسئله)](#د-دې-پر-ځای-چې-query-په-blade-کې-ولیکئ-د-eager-loading-څخه-کار-واخلئ-n1-مسئله)
[د ډېرې ډېټا لپاره د ډېټا چنک (data chunk) نه استفاده وکړئ](#د-ډېرې-ډېټا-لپاره-د-ډېټا-چنک-data-chunk-نه-استفاده-وکړئ)
[تبصرې وکړئ (Comments)، مګر د متودونو یا متغیرونو نومونه توضیحي او معنی لرونکي په پام کې ونیسئ.](#تبصرې-وکړئ-comments-مګر-د-متودونو-یا-متغیرونو-نومونه-توضیحي-او-معنی-لرونکي-په-پام-کې-و-نیسئ)
[په Blade ټیمپلیټونو کې له js او css څخه کار مه اخلئ او هېڅ HTML کوډ په PHP class کې مه کاروئ.](#په-blade-ټیمپلیټونو-کې-له-js-او-css-څخه-کار-مه-اخلئ-او-هېڅ-html-کوډ-په-php-class-کې-مه-کاروئ)
[پر ځای د مستقیم متنونو څخه په کوډ کې، د config او languages فایلونو څخه کار واخلئ!](#پر-ځای-د-مستقیم-متنونو-څخه-په-کوډ-کې-د-config-او-languages-فایلونو-څخه-کار-واخلئ)
[د لاراول د معیاري وسایلو څخه چې د لاراول ټولنې یا کمیونیټي لخوا تایید شوي دي کار واخلئ](#د-لاراول-د-معیاري-وسایلو-څخه-چې-د-لاراول-ټولنې-یا-کمیونیټي-لخوا-تایید-شوي-دي-کار-واخلئ)
[د لاراول د نومونو له اصولو څخه کار واخلئ.](#د-لاراول-د-نومونو-له-اصولو-څخه-کار-واخلئ)
[کنوانسیون د تنظیماتو په پرتله غوره دی](#کنوانسیون-د-تنظیماتو-په-پرتله-غوره-دی)
[تر حده پورې په خپل کوډ کې، د معنی لرونکي او لنډ Syntax څخه کار واخلئ.](#تر-حده-پورې-په-خپل-کوډ-کې-د-معنی-لرونکي-او-لنډ-syntax-څخه-کار-واخلئ)
[د object د جوړولو په وخت کې د new کیورد پر ځای IoC container او facades څخه کار واخلئ](#د-object-د-جوړولو-په-وخت-کې-د-new-کیورد-پر-ځای-ioc-container-او-facades-څخه-کار-واخلئ)
[له .env فایل څخه هېڅ وخت مستقیم ډېټا مه ترلاسه کوئ.](#له-env-فایل-څخه-هېڅ-وخت-مستقیم-ډېټا-مه-ترلاسه-کوئ)
[تاریخ او وخت په معیاري بڼه کې ذخیره کړئ. د تاریخ او وخت د ښودلو لپاره له Accessors & Mutators څخه کار واخلئ.](#تاریخ-او-وخت-په-معیاري-بڼه-کې-ذخیره-کړئ-د-تاریخ-او-وخت-د-ښودلو-لپاره-له-accessors--mutators-څخه-کار-واخلئ)
[ډاټ بلاک مه استفاده کوئ](#ډاټ-بلاک-مه-استفاده-کوئ)
[نورې ښې طریقې](#نورې-ښې-طریقې)
### **د یوه مسؤلیت اصل**
یو کلس باید یوه وظیفه ولري.
بد کوډ:
```php
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();
}
```
ښه کوډ:
```php
public function update(UpdateRequest $request): string
{
$this->logService->logEvents($request->events);
$this->event->updateGeneralEvent($request->validated());
return back();
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **میتودونه باید یوازې یو کار ترسره کړي**
یو فنکشن باید یوازې یو کار ترسره کړي او باید په ښه شکل یې ترسره کړي.
بد کوډ:
```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;
}
}
```
ښه کوډ:
```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;
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **لوی ماډلونه، کوچني کنټرولرونه!**
د ډېټابیس مربوط شیان په Eloquent models کې ولیکئ.
بد کوډ:
```php
public function index()
{
$clients = Client::verified()
->with(['orders' => function ($q) {
$q->where('created_at', '>', Carbon::today()->subWeek());
}])
->get();
return view('index', ['clients' => $clients]);
}
```
ښه کوډ:
```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();
}
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **ډېټا تصدیق یا اعتبار**
د ډېټا تصدیق یا ولیدیشن د کنټرولرونو پر ځای په Request classess کې ولیکئ.
بد کوډ:
```php
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
...
}
```
ښه کوډ:
```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',
];
}
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **د پروګرام منطق باید په service class کې وي**
یو کنټرولر باید یوازې یو مسؤلیت ولري، نو د کوډ منطق په د کنټرولرونو پر ځای باید په service classes کې ولیکئ.
بد کوډ:
```php
public function store(Request $request)
{
if ($request->hasFile('image')) {
$request->file('image')->move(public_path('images') . 'temp');
}
...
}
```
ښه کوډ:
```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');
}
}
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **د DRY اصل یا خپل ځان مه تکراروه**
کوډ یو وار ولیکئ او ډېر ځایه یې استعمال کړی د کوډ د تکرار څخه ډډه وکړئ.
همچنان Blade templates کوډ هم مه تکراروئ، د Eloquent scope څخه استفاده وکړئ.
بد کوډ:
```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();
}
```
ښه کوډ:
```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();
}
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **د Query Builder او raw SQL queries پر ځای باید د Eloquent ORM څخه کار واخیستل شي. او همچنان د Arrays پر ځای د Collections څخه کار واخیستل شي**
د Eloquent په واسېه تاسې کولی شئ چې کوډ ویونکي او -هغه چا ته چې وروسته په کوډ کې تغییرات راولی- ته آسانه کوډ ولیکئ.
همچنان Eloquent مخکې جوړ شوي شیان لري لکه soft deletes, events, scopes وغیره
[Eloquent SQL ته مرجع](https://github.com/alexeymezenin/eloquent-sql-reference).
بد کوډ:
```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
```
ښه کوډ:
```php
Article::has('user.profile')->verified()->latest()->get();
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **(Mass assignment) ډله ایزه دنده**
بد کوډ:
```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();
```
ښه کوډ:
```php
$category->article()->create($request->validated());
```
[🔝 بېرته تګ منځپانګو ته](#د-منځپانګو-یا-مطالبو-نوملړ
)
### **د دې پر ځای چې query په blade کې ولیکئ د eager loading څخه کار واخلئ. (N+1 مسئله)**
بد کوډ (د ۱۰۰ کارنو لپاره ۱۰۱ کیوریانې رن کوي):
```blade
@foreach (User::all() as $user)
{{ $user->profile->name }}
@endforeach
```
ښه کوډ (for 100 users, 2 DB queries will be executed):
ښه کوډ (د ۱۰۰ کارنو لپاره ۲ کیوریانې رن کوي):
```php
$users = User::with('profile')->get();
gitextract_g1v8989h/ ├── README.md ├── arabic.md ├── bangla.md ├── burmese.md ├── chinese.md ├── french.md ├── german.md ├── images/ │ └── logo-language.psd ├── indonesia.md ├── italian.md ├── japanese.md ├── pashto.md ├── persian.md ├── polish.md ├── romanian.md ├── russian.md ├── spanish.md ├── thai.md ├── traditional-chinese.md ├── turkish.md ├── turkmen.md ├── ukrainian.md └── urdu.md
Condensed preview — 23 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (438K chars).
[
{
"path": "README.md",
"chars": 21918,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "arabic.md",
"chars": 19889,
"preview": "\n\nYou might also want to check out the [real-world Laravel ex"
},
{
"path": "bangla.md",
"chars": 18387,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "burmese.md",
"chars": 22750,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "chinese.md",
"chars": 13751,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "french.md",
"chars": 19242,
"preview": "\n\nYou might also want to check out the [real-world Laravel ex"
},
{
"path": "german.md",
"chars": 20009,
"preview": "\n\nYou might also want to check out the [real-world Laravel ex"
},
{
"path": "indonesia.md",
"chars": 17396,
"preview": "\n\n\nYou might also want to check out the [real-world Laravel "
},
{
"path": "italian.md",
"chars": 18743,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "japanese.md",
"chars": 14782,
"preview": "\n\nYou might also want to check out the [real-world Laravel examp"
},
{
"path": "pashto.md",
"chars": 23371,
"preview": "\n\nYou might also want to check out the [rea"
},
{
"path": "persian.md",
"chars": 21342,
"preview": "\n\nYou might also wan"
},
{
"path": "polish.md",
"chars": 19302,
"preview": "\n\nYou might also want to check out the [real-world Lara"
},
{
"path": "romanian.md",
"chars": 20253,
"preview": "\n\nTe poate interesa si [exemplul real de aplicație Lar"
},
{
"path": "russian.md",
"chars": 20959,
"preview": "\n\nВозможно, вам также будет интересно взглянуть на [пример"
},
{
"path": "spanish.md",
"chars": 19708,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "thai.md",
"chars": 19676,
"preview": "\n\nYou might also want to check out the [real-world Laravel exa"
},
{
"path": "traditional-chinese.md",
"chars": 13158,
"preview": "\n\nYou might also want to check out the [real-wor"
},
{
"path": "turkish.md",
"chars": 18588,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
},
{
"path": "turkmen.md",
"chars": 20598,
"preview": "\n\nŞeýle hem, [Laravel mysal programmasyna](https://github.co"
},
{
"path": "ukrainian.md",
"chars": 17543,
"preview": "\n\nYou might also want to check out the [real-world Lara"
},
{
"path": "urdu.md",
"chars": 20006,
"preview": "\n\nYou might also want to check out the [real-world Laravel e"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the alexeymezenin/laravel-best-practices GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 23 files (411.5 KB), approximately 126.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.