ربما لا يخلو أي مشروع من علاقة one-to-may بين الـ models، حيث يمكن جلب جميع السجلات لـ model معين، لكن ببعض الأحيان قد يتطلب الأمر جلب سجل معين من العلاقة وليس جميع السجلات.
مثال : لفرض أن لدينا User Model و Post Model، وكل User له مجموعة من Post ، ونريد جلب فقط أخر Post تمت إضافته من قبل هذا الـ User.
جدول posts
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->integer('views');
$table->foreignId('user_id')->constrained();
$table->timestamps();
});بالطبع يمكن عمل ذلك من خلال جملة eloquent
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}$users=User::with(['posts'=>function ($query) {
$query->orderBy('id', 'DESC')->first();
}])->first();
return $users;إلا إنه عوضا عن جملة eloquent بالأعلى يمكن القيام بذلك من خلال الـ model من خلال إستخدام latestOfMany
الدالة latestOfMany في لارافيل
بداية نذهب إلى User Model وننشئ علاقة جديده لتكن مثلا بإسم lastPost، ونغير نوع العلاقة من hasMany إلى hasOne ومن ثم نمرر latestOfMany
public function lastPost()
{
return $this->hasOne(Post::class)->latestOfMany();
}الأن في جملة eloquent نستخدم العلاقة الجديده
$users = User::with('lastPost')->first();الدالة oldestOfMany في لارافيل
كذلك إذا أردنا الحصول على أول Post قام الـ user بإنشاؤه، يمكن إستخدام oldestOfMany، حيث نقوم بإنشاء علاقة جديده مثلا بإسم oldestPost، وإيضا إستخدام العلاقة hasOne ومن ثم تمرير oldestOfMany
public function oldestPost()
{
return $this->hasOne(Post::class)->oldestOfMany();
}$users = User::with('oldestPost')->first();الدالة ofMany في لارافيل
كما شاهدنا بالأعلى أنا الدوال latestOfMany و oldestOfMany تقوم بإرجاع أول سجل و أخر سجل، لكن ببعض الأحيان قد يتطلب الأمر إسترجاع سجلات بشروط أخرى، على سبيل المثال إذا أردنا إرجاع user post التي لها أعلى عدد من المشاهدات.
هنا ننشئ علاقة مثلا بإسم popularPost ونستخدم ofMany ونمرر لها الحقل الذي نريد الترتيب من خلالة (views, id, updated_at...)، ومن ثم الدالة min, max، في حالتنا بما إننا نريد عدد المشاهدات سوف نستخدم الحقل views
public function popularPost()
{
return $this->hasOne(Post::class)->ofMany('views', 'max');
}$users = User::with('popularPost')->first();كما يمكن أيضا إستخدام clousure function كـ second argument ، مثلا إذا كنا نريد جلب user post التي لها أعلى عدد من المشاهدات ، لكن المشاهدات أقل من 1000.
public function popularPost()
{
return $this->hasOne(Post::class)
->ofMany(['views'=>'max'], function ($q){
$q->where('views','<','200');
});
}$users = User::with('popularPost')->first();مثال أخر: لفرض أردنا أن نجلب أخر post من حيث id , وأن يكون أخر post تم التعديل عليه.
public function maxUpdatedAtOrder(){
return $this->hasOne(Post::class)->ofMany(['id'=>'max', 'updated_at'=>'max']);
}مثال أخر : لفرض أردنا أن نجلب أخر post من حيث id و يكون أخر post تم التعديل عليه، ويكون العنوان يحتوي على كلمة palestine
public function maxWithCondition(){
return $this->hasOne(Post::class)
->ofMany(['id'=>'max', 'updated_at'=>'max'], function ($q){
$q->where('title','like','%palestine%');
});
}
مقال تحفة ربنا يكرمك
شكراً لك 🌱 سعيد أن المقال نال إعجابك.
شكرا لك ، سؤالي هل لابد من استخدام ( العلاقة ) قبل البحث ؟ الا يكفي في laravel استخدام mysql select statment فقط
شكرًا لسؤالك. لا، ليس إلزاميًا استخدام العلاقة (hasOne/ofMany) — يمكنك تمامًا كتابة استعلام SQL خام أو استخدام Query Builder للوصول لنفس النتيجة، وستحصل على نفس البيانات في النهاية.
الفائدة من استخدام العلاقة تكمن في:
فباختصار: MySQL select كافٍ من الناحية الوظيفية، لكن العلاقة توفر عليك التكرار وتُحسّن الأداء عند التعامل مع مجموعات، وتحافظ على الكود منظمًا ضمن فلسفة Eloquent.
مقال ممتاز وموضوع مش كتير واخد باله منه شكرا جدا وجزاك الله خيرا
شكرًا جزيلًا لك، وجزاك الله خيرًا. فعلًا هذا الموضوع من الأشياء المفيدة لكنها غير معروفة بشكل كافٍ رغم أنها موجودة في Laravel منذ فترة. سعيد أن المقال أفادك.
بارك الله فيك و زادك من علمه مقال جميل و مفيد و نتمنى المزيد
وفيك بارك الله، شكرًا لتشجيعك. إن شاء الله المزيد من المقالات قادم قريبًا.
مقال جميل جدا.. مبارك التصميم الجديد للمدونة.. عندي ملاحظة بسيطة وهي تغيير الخط في الكود إلى خط monospace كما في محررات الكود، فهذا أسهل في القراءة
شكرًا جزيلًا على الملاحظة، وسعيد أن التصميم الجديد عجبك. ملاحظتك في محلها فعلًا — خط monospace يجعل الكود أوضح للقراءة (خصوصًا للمسافات والأقواس). سأعمل على تعديل الستايل الخاص بعناصر pre/code في المدونة قريبًا. تسلم على المتابعة والاهتمام بالتفاصيل.
very good
Thank you very much! Glad you found it useful.