Nederlands (by Protoqol)
한국어 (by cherrypick)
ภาษาไทย (by kongvut sangkla)
বাংলা (by Anowar Hossain)
فارسی (by amirhossein baghaie)
Українська (by Tenevyk)
Tiếng Việt (by Chung Nguyễn)
Español (by César Escudero)
Français (by Mikayil S.)
Polski (by Maciej Jeziorski)
Deutsch (by Sujal Patel)
Italiana (by Sujal Patel)
Azərbaycanca (by Maharramoff)
العربية (by ahmedsaoud31)
هذا المحتوى لا يصنف كمبادئ SOLID للارافيل أو أنماط التصميم، إلخ... هنا ستجد أفضل الممارسات التي يتم تجاهلها عادةً في مشاريع لارافيل الفعلية.
نمط المسئولية الواحدة
كود أكثر في النماذج، كود أقل في المتحكمات
الفلترة
الأكواد المنطقية يجب أن تكون في فئة خادمة منفصلة
لا تكرر نفس الكود
يفضل استخدام نظام التعامل مع قواعد البيانات والمسمى ب Eloquent عن استخدام باني الإستعلامات Query Builder أو الإستخدام المباشر لأوامر الإستعلامات SQL عبر raw، ويفضل استخدام المجموعات عن المصفوفات
تقليص المهام
لا تقم بتنفيذ الإستعلامات داخل ملفات blade واستخدم التحميل الحثيث مشكلة (N+1)
اضف التعليقات للكود ويفضل استخدام صيع التعليقات القياسية للمتغيرات والخواص والقيم المعادة إلخ
لا تضع شفرات js و css داخل ملفات Blade ولا تضع أي شفرات HTML في فئات php
استخدم ملفات الإعدادت واللغات, والثوابت بدلاً من النص داخل الكود
استخدم الأدوات القياسية المعتمدة من مجتمع لارافيل
اتبع طريقة لارافيل في التسميات
استخدم كود أقصر قابل للقراءة والفهم السريع قدر المستطاع
استخدم الحاويات أو الواجهات بدلاً من الفئات الجديدة
لا تقم بجلب البيانات من ملف .env
احفظ البيانات في الشكل القياسي. استخدم المسترجعات والمُعدلات في تعديل شكل صيغة التاريخ
ممارسات جيدة أخر
وظيفة الفئة والطريقة يجب ان تكون مسئولية واحدة فقط، بمعنى أخر يجب ألا تكون الفئة أو الطريقة متعددة المهام وجيب أن تختص بمهمة واحدة فقط
❌ طريقة سيئة:
public function getFullNameAttribute()
{
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()
{
return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();
}
public function isVerifiedClient()
{
return auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified();
}
public function getFullNameLong()
{
return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}
public function getFullNameShort()
{
return $this->first_name[0] . '. ' . $this->last_name;
}
🔝 الرجوع للفهرس
ضع كل الأكواد الخاصة بالتعامل مع قواعد البيانات في فئات خاصة منفصلة ولا تضعها في المتحكمات
❌ طريقة سيئة:
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();
}
}
🔝 الرجوع للفهرس
انقل أكواد الفلترة من المتحكمات الي فئات الطلبات 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',
];
}
}
🔝 الرجوع للفهرس
المتحكم يجب أن يكون له مسئولية واحدة فقط، أنقل الأكواد المنطقية لفئات خادمة منفصلة
❌ طريقة سيئة:
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');
}
}
}
🔝 الرجوع للفهرس
اعد استخدام نفس الكود قدر المستطاع ولا تقم بإعادة كتابته سيساعدك هذا على عدم وجود أكثر من كود لتنفيذ نفس المهمة، وإعادة استخدام قوالب 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();
}
🔝 الرجوع للفهرس
يفضل استخدام نظام التعامل مع قواعد البيانات والمسمى ب 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();
🔝 الرجوع للفهرس
❌ طريقة سيئة:
$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());
🔝 الرجوع للفهرس
❌ طريقة سيئة:
~لعدد 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
🔝 الرجوع للفهرس
❌ طريقة سيئة:
if (count((array) $builder->getQuery()->joins) > 0)
طريقة أفضل:
// Determine if there are any joins.
if (count((array) $builder->getQuery()->joins) > 0)
✔️ طريقة جيدة:
if ($this->hasJoins())
🔝 الرجوع للفهرس
❌ طريقة سيئة:
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();
الطريقة الأفضل هو استخدام الحزم الخاصة بنقل البيانات من بي إتش بي إلى جافا سكريبت.
🔝 الرجوع للفهرس
❌ طريقة سيئة:
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'));
🔝 الرجوع للفهرس
يفضل استخدام الأدوات المدمجة مع إطار عمل لارافيل والحزم المقترحة من مجتمع لارفيل عن استخدام غيرها، أي مطور سيعمل على تطبيقك في وقت لاحق سيحتاج لتعلم تلك الأدوات التي لا يشيع استخدامها في تطبيقات لارافيل، وأيضاً أطلب المساعدة من مجتمع لارافيل عندما تقرر الإعتماد على أحد الأدوات او الحزم، ولا تجع عميلك يدفع مقابل ذلك.
الوظيفة | الأدوات القياسية | أدوات الطرف الثالث |
---|---|---|
Authorization | Policies | Entrust, Sentinel and other packages |
Compiling assets | Laravel Mix | Grunt, Gulp, 3rd party packages |
Development Environment | Homestead | Docker |
Deployment | Laravel Forge | Deployer and other solutions |
Unit testing | PHPUnit, Mockery | Phpspec |
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 | 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.
وأيضاً, راجع اصطلاح التسميات المقبول من جهه مجتمع لارافيل:
ماذا | كيف | جيدة | سيئة |
---|---|---|---|
Controller | singular | ArticleController | |
Route | plural | articles/1 | |
Named route | snake_case with dot notation | users.show_active | |
Model | singular | User | |
hasOne or belongsTo relationship | singular | articleComment | |
All other relationships | plural | articleComments | |
Table | plural | article_comments | |
Pivot table | singular model names in alphabetical order | article_user | |
Table column | snake_case without model name | meta_title | |
Model property | snake_case | $model->created_at | |
Foreign key | singular model name with _id suffix | article_id | |
Primary key | - | id | |
Migration | - | 2017_01_01_000000_create_articles_table | |
Method | camelCase | getAll | |
Method in resource controller | table | store | |
Method in test class | camelCase | testGuestCannotSeeArticle | |
Variable | camelCase | $articlesWithAuthor | |
Collection | descriptive, plural | $activeUsers = User::active()->get() | |
Object | descriptive, singular | $activeUser = User::active()->first() | |
Config and language files index | snake_case | articles_enabled | |
View | kebab-case | show-filtered.blade.php | |
Config | snake_case | google_calendar.php | |
Contract (interface) | adjective or noun | Authenticatable | |
Trait | adjective | Notifiable |
🔝 الرجوع للفهرس
❌ طريقة سيئة:
$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') |
🔝 الرجوع للفهرس
إنشاء فئات جديدة يخلق شئ من التشويش بين الفئات ويعقد عملة الإختبار، الأفضل الإعتماد على الحاويات او الواجهات في هذا الأمر
❌ طريقة سيئة:
$user = new User;
$user->create($request->validated());
✔️ طريقة جيدة:
public function __construct(User $user)
{
$this->user = $user;
}
....
$this->user->create($request->validated());
🔝 الرجوع للفهرس
مرر البيانات لملف الإعدادت ومن ثَم استخدم الدالة المساعدة `config()` لاستخدامها في جلب البيانات المخزنة في ملف الإعدادت داخل تطبيقك.
❌ طريقة سيئة:
$apiKey = env('API_KEY');
✔️ طريقة جيدة:
// config/api.php
'key' => env('API_KEY'),
// Use the data
$apiKey = config('api.key');
🔝 الرجوع للفهرس
❌ طريقة سيئة:
{{ 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 $dates = ['ordered_at', 'created_at', 'updated_at'];
public function getSomeDateAttribute($date)
{
return $date->format('m-d');
}
// ملف العرض
{{ $object->ordered_at->toDateString() }}
{{ $object->ordered_at->some_date }}
🔝 الرجوع للفهرس
لا تضع أي شيفرة برمجية في ملفات الموجهات.
قلل من استخدامك الشيفرات البرمجية المنطقية في ملفات العرض blade.
🔝 الرجوع للفهرس