Skip to content

Latest commit

 

History

History
640 lines (475 loc) · 23.2 KB

arabic.md

File metadata and controls

640 lines (475 loc) · 23.2 KB

Laravel best practices

You might also want to check out the real-world Laravel example application

الترجمات

Nederlands (by Protoqol)

한국어 (by cherrypick)

日本語 (by 2bo)

漢語 (by xiaoyi)

ภาษาไทย (by kongvut sangkla)

বাংলা (by Anowar Hossain)

فارسی (by amirhossein baghaie)

Português (by jonaselan)

Українська (by Tenevyk)

Русский

Tiếng Việt (by Chung Nguyễn)

Español (by César Escudero)

Français (by Mikayil S.)

Polski (by Karol Pietruszka)

Türkçe (by Burak)

Deutsch (by Sujal Patel)

Italiana (by Sujal Patel)

Azərbaycanca (by Maharramoff)

العربية (by ahmedsaoud31)

اردو (by RizwanAshraf1)

Laravel example app

الفهرس

نمط المسؤولية الواحدة

شيفرة أكثر في النماذج، شيفرة أقل في المتحكمات

التحقق

الشيفرات المنطقية يجب أن تكون في فئة خادمة منفصلة

لا تكرر نفس الشيفرة

،

يفضل استخدام نظام التعامل مع قواعد البيانات المسمى بـEloquent بدل استخدام باني الإستعلامات Query Builder أو الاستخدام المباشر لأوامر الإستعلامات SQL عبر raw، ويفضل استخدام المجموعات بدل المصفوفات

تقليص المهام

لا تقم بتنفيذ الإستعلامات داخل ملفات blade واستخدم التحميل الحثيث مشكلة (N+1)

اضف التعليقات للشيفرة ويفضل استخدام صيغ التعليقات القياسية للمتغيرات والخواص والقيم المعادة إلخ

لا تضع شيفرات js و css داخل ملفات Blade ولا تضع أي ششفرات HTML في فئات php

استخدم ملفات الإعدادت واللغات، والثوابت بدلاً من النص داخل الشيفرة

استخدم الأدوات القياسية المعتمدة من مجتمع لارافيل

اتبع طريقة لارافيل في التسميات

استخدم شيفرة أقصر قابلة للقراءة والفهم السريع قدر المستطاع

استخدم الحاويات أو الواجهات بدلاً من الفئات الجديدة

لا تقم بجلب البيانات من ملف .env

احفظ البيانات في الشكل القياسي. استخدم المسترجعات والمُعدلات في تعديل شكل صيغة التاريخ

ممارسات جيدة أخرى

1

نمط المسئولية الواحدة

وظيفة الفئة والطريقة يجب أن تكون مسئولية واحدة فقط، بمعنى آخر يجب ألا تكون الفئة أو الطريقة متعددة المهام ويجب أن تختص بمهمة واحدة فقط

❌ طريقة سيئة:

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;
    }
}

✔️ طريقة جيدة:

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;
}

🔝 الرجوع للفهرس

2

شيفرة أكثر في النماذج، شيفرة أقل في المتحكمات

ضع كل الشيفرات الخاصة بالتعامل مع قواعد البيانات في فئات خاصة منفصلة ولا تضعها في المتحكمات

❌ طريقة سيئة:

public function index()
{
    $clients = Client::verified()
        ->with(['orders' => function ($q) {
            $q->where('created_at', '>', Carbon::today()->subWeek());
        }])
        ->get();

    return view('index', ['clients' => $clients]);
}

✔️ طريقة جيدة:

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();
    }
}

🔝 الرجوع للفهرس

3

التحقق

انقل شيفرات التحقق من المتحكمات إلى فئات الطلبات Request classes

❌ طريقة سيئة:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
        'publish_at' => 'nullable|date',
    ]);

    ...
}

✔️ طريقة جيدة:

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',
        ];
    }
}

🔝 الرجوع للفهرس

4

الشيفرات المنطقية يجب أن تكون في فئة خادمة منفصلة

المتحكم يجب أن يكون له مسئولية واحدة فقط، أنقل الشيفرات المنطقية لفئات خادمة منفصلة

❌ طريقة سيئة:

public function store(Request $request)
{
    if ($request->hasFile('image')) {
        $request->file('image')->move(public_path('images') . 'temp');
    }
    
    ...
}

✔️ طريقة جيدة:

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');
        }
    }
}

🔝 الرجوع للفهرس

5

لا تكرر نفس الشيفرة

أعد استخدام نفس الشيفرة قدر المستطاع ولا تقم بإعادة كتابتها، سيساعدك هذا على عدم وجود أكثر من شيفرة لتنفيذ نفس المهمة، وإعادة استخدام قوالب blade وفئات التعامل مع قواعد البيانات Eloquent

مثال استخدم scope في فئات التعامل مع قواعد البيانات Eloquent

❌ طريقة سيئة:

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();
}

✔️ طريقة جيدة:

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();
}

🔝 الرجوع للفهرس

6

يفضل استخدام نظام التعامل مع قواعد البيانات المسمى بـEloquent بدل استخدام باني الإستعلامات Query Builder أو الاستخدام المباشر لأوامر الإستعلامات SQL عبر raw، ويفضل استخدام المجموعات بدل المصفوفات

Eloquent يجعلك تكتب شيفرة قابلة للقراءة والصيانة. وأيضاً، Eloquent يحتوي على أدوات وخواص داخلية على سبيل الذكر: الحذف الناعم والأحداث والنطاقات إلخ...

❌ طريقة سيئة:

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

✔️ طريقة جيدة:

Article::has('user.profile')->verified()->latest()->get();

🔝 الرجوع للفهرس

7

تقليص المهام

❌ طريقة سيئة:

$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();

✔️ طريقة جيدة:

$category->article()->create($request->validated());

🔝 الرجوع للفهرس

8

لا تقم بتنفيذ الإستعلامات داخل ملفات blade واستخدم التحميل الحثيث مشكلة (N+1)

❌ طريقة سيئة:

~لعدد 100 مستخدم سيُنفذ 101 استعلام على قاعدة البيانات

@foreach (User::all() as $user)
    {{ $user->profile->name }}
@endforeach

✔️ طريقة جيدة:

~لعدد 100 مستخدم سيُنفذ 2 استعلام فقط على قاعدة البيانات~

$users = User::with('profile')->get();

@foreach ($users as $user)
    {{ $user->profile->name }}
@endforeach

🔝 الرجوع للفهرس

9

اضف التعليقات للشيفرة، ويفضل استخدام صيغ التعليقات القياسية للمتغيرات والخواص والقيم المعادة إلخ

❌ طريقة سيئة:

if (count((array) $builder->getQuery()->joins) > 0)

طريقة أفضل:

// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)

✔️ طريقة جيدة:

if ($this->hasJoins())

🔝 الرجوع للفهرس

10

لا تضع شيفرات js و css داخل ملفات Blade ولا تضع أي شيفرات HTML في فئات php

❌ طريقة سيئة:

let article = `{{ json_encode($article) }}`;

✔️ طريقة أفضل:

<input id="article" type="hidden" value='@json($article)'>

Or

<button class="js-fav-article" data-article='@json($article)'>{{ $article->name }}<button>

في ملف جافا سكريبت:

let article = $('#article').val();

الطريقة الأفضل هي استخدام الحزم الخاصة بنقل البيانات من PHP إلى جافا سكريبت.

🔝 الرجوع للفهرس

11

استخدم ملفات الإعدادت واللغات، والثوابت بدلاً من النص داخل الشيفرة

❌ طريقة سيئة:

public function isNormal()
{
    return $article->type === 'normal';
}

return back()->with('message', 'Your article has been added!');

✔️ طريقة جيدة:

public function isNormal()
{
    return $article->type === Article::TYPE_NORMAL;
}

return back()->with('message', __('app.article_added'));

🔝 الرجوع للفهرس

12

استخدم الأدوات القياسية المعتمدة من مجتمع لارافيل

يفضل استخدام الأدوات المدمجة مع إطار عمل لارافيل والحزم المقترحة من مجتمع لارفيل بدل استخدام غيرها، أي مطور سيعمل على تطبيقك في وقت لاحق سيحتاج إلى تعلم تلك الأدوات التي لا يشيع استخدامها في تطبيقات لارافيل، وأيضاً أطلب المساعدة من مجتمع لارافيل عندما تقرر الإعتماد على أحد الأدوات أو الحزم، ولا تجعل عميلك يدفع مقابل ذلك.

الوظيفة الأدوات القياسية أدوات الطرف الثالث
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

🔝 الرجوع للفهرس

13

اتبع طريقة لارافيل في التسميات

راجع PSR standards

وأيضا، راجع اصطلاح التسميات المقبول من جهه مجتمع لارافيل:

ماذا كيف جيدة سيئة
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 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) adjective NotifiableTrait Notification
Enum singular UserType UserTypes, UserTypeEnum
FormRequest singular UpdateUserRequest UpdateUserFormRequest, UserFormRequest, UserRequest
Seeder singular UserSeeder UsersSeeder

🔝 الرجوع للفهرس

14

استخدم شيفرة أقصر قابلة للقراءة والفهم السريع قدر المستطاع

❌ طريقة سيئة:

$request->session()->get('cart');
$request->input('name');

✔️ طريقة جيدة:

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')

🔝 الرجوع للفهرس

15

استخدم الحاويات أو الواجهات بدلاً من الفئات الجديدة

إنشاء فئات جديدة يخلق شيئا من التشويش بين الفئات ويعقد عملة الإختبار، الأفضل الإعتماد على الحاويات أو الواجهات في هذا الأمر

❌ طريقة سيئة:

$user = new User;
$user->create($request->validated());

✔️ طريقة جيدة:

public function __construct(User $user)
{
    $this->user = $user;
}

...

$this->user->create($request->validated());

🔝 الرجوع للفهرس

16

لا تقم بجلب البيانات من ملف .env مباشرة

مرر البيانات لملف الإعدادت ومن ثَم استخدم الدالة المساعدة `config()` لاستخدامها في جلب البيانات المخزنة في ملف الإعدادت داخل تطبيقك.

❌ طريقة سيئة:

$apiKey = env('API_KEY');

✔️ طريقة جيدة:

// config/api.php
'key' => env('API_KEY'),

// Use the data
$apiKey = config('api.key');

🔝 الرجوع للفهرس

17

خزن التواريخ بأشكالها القياسية، واستخدم المسترجعات والمُعدلات لتعديل صيغة التواريخ كما تريد.

❌ طريقة سيئة:

{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }}
{{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->format('m-d') }}

✔️ طريقة جيدة:

// Model
protected $casts = [
    'ordered_at' => 'datetime',
];

public function getSomeDateAttribute($date)
{
    return $date->format('m-d');
}

// ملف العرض
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}

🔝 الرجوع للفهرس

18

ممارسات جيدة أخرى

لا تضع أي شيفرة برمجية في ملفات الموجهات.

قلل من استخدامك الشيفرات البرمجية المنطقية في ملفات العرض blade.

🔝 الرجوع للفهرس