في هذا المقال سأحاول توضيح فكرة query scopes، حيث يوجد منه نوعان globally, locally. والفائدة من إستخدام scope أنه يمكننا من تجميع جمل الـ query المتكرره في الـ controller، بمعنى أخر عدم تكرار الكود
Local Scope
لفرض لدينا المثال التالي
public function index(){ $articles = Article::where('active', 1)->get(); } public function search(Request $request){ $articles = Article::where('active', 1) ->where('title', $request->title) ->get(); }
كما نلاحظ بالكود أعلاه فإننا قمنا بتكرار where(‘active’,1) في الدالتين، إلا إنه في eloquent يمكن تجنب ذلك كي يصبح الكود أكثر إحترافية، ولمنع التكرار يجب الذهاب على article model ونعرف دالة تقوم فقط بإرجاع شرطwhere(‘active’,1)
//in article Model public function scopeActive($query){ return $query->where('active', 1); }
كما نلاحظ أن تعريف scope يتم من خلال كتابة كلمة scope ثم أي إسم لكن الحرف الأول capital.
ولإستخدام هذه الدالة في eloquent بداخل الـ controller
public function index(){ $articles = Article::active()->get(); } public function search(Request $request){ $articles = Article::active() ->where('titel', $request->title) ->get(); }
نستخدم scope من خلال كتابة إسم scope الذي قمنا بتعريفه في الـ model دون كتابة كلمة scope
مثال أخر
في هذا المثال فإننا نريد إرجاع جميع المقالات التي تم كتابتها خلال 30 يوم
//in ArticleModel public function scopeNewest($query){ return $query->where('created_at', '>', now()->subDays(30)) }
//Controller public function index(){ $articles = Article::active()->newest()->get(); } public function search(Request $request){ $articles = Article::active()->newest() ->where('titel', $request->title) ->get(); }
لكن السؤال ، ماذا لو أردنا داخل الدالة index إرجاع المقالات التي كتبت خلال 30 يوم، أما في البحث نريد إرجاع المقالات التي كتبت خلال 10 أيام، كيف سنتعامل مع هذه الحالة بإستخدام scope واحد
لحل هذه المشكله يمكن إستخدام parameter في scope
public function scopeNewest($query, $days){ return $query->where('created_at', '>', now()->subDays($days)); }
وفي eloquent يمكن تمرير أي رقم (يوم) نريده
public function index(){ $articles = Article::active()->newest(30)->get(); } public function search(Request $request){ $articles = Article::active()->newest(10) ->where('titel', $request->title) ->get(); }
Global Scope
كما رأينا في الأمثلة أعلاه، فإننا قمنا بتعريف scope بداخل الـ model وتم إستدعاءه في الـ controller ، لكن يوجد طريقة أخرى للتعامل مع scope من خلال تعريف global Scope بداخل model
يتم تعريف global scope بداخل model من خلال booted function وبداخلها addGGlobal Scope.
يوجد طريقتين لكتابة Global Scope
الطريقة الأولى : بداخل الموديل مباشرة
//ArticleModel use Illuminate\Database\Eloquent\Builder; protected static function booted(){ static::addGlobalScope('active', function (Builder $builder) { $builder->where('active', 1); }); }
و في الـ controller بداخل function يتم كتابه الـ function مباشرة دون إستدعاء الـ scope
//Controller public function index(){ $articles = Article::get(); return view('/article', compact('articles')); } public function search(Request $request){ $articles = Article::where('titel', $request->title)->get(); return view('/article', compact('articles')); }
الطريقة الثانية : إنشاء كلاس منفصل
كما يوجد طريقة أخرى لكتابة Global Scope من خلال إنشاء Global Scope Class أي كلاس منفصل ، هنا سأقوم بإنشاء Global Scope Class بإسم ActiveSope
php artisan make:scope ActiveScope
بعد تنفيذ الأمر، سيتم إنشاء كلاس جديد بإسم ActiveScope بداخل مجلد Scopes بداخل المجلد Models
<?php namespace App\Models\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; class ArticleScope implements Scope { public function apply(Builder $builder, Model $model) { $builder->where('active',1); } }
وفي الـ Article Model بداخل الدالة booted يمكن إستدعاء هذا الكلاس
class Article extends Model { use HasFactory; public static function booted() { static::addGlobalScope(new ActiveScope()); } }
لكن ماذا لو قمنا بإنشاء Global Scope لكن لا أريد أن يتم تطبيقها على دالة معينة.
هنا يمكن لنا إستخدام الدالة withoutGlobalScopes
public function index() { $articles=Article::withoutGlobalScopes()->get(); return $articles; }
يعطيك العافية جدا جميل العمل و الجميل أنه يتم التركيز على أمور متقدمة وغير مفهومة في اللارافيل . بتمنى تستمر في هذه المقالات المفيدة كل الدعم و التشجيع.
شرح جميل ممتاز جدا جزاك الله خيرا
الف مليون شكر لحضرتك
يعطيكم العافيه
Mogahid gaffar
شرح جميل للغايه ! مشكور