ربما لا يخلو أي مشروع من علاقة 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
بداية نذهب إلى User Model وننشئ علاقة جديده لتكن مثلا بإسم lastPost، ونغير نوع العلاقة من hasMany إلى hasOne ومن ثم نمرر latestOfMany
public function lastPost() { return $this->hasOne(Post::class)->latestOfMany(); }
الأن في جملة eloquent نستخدم العلاقة الجديده
$users = User::with('lastPost')->first();
كذلك إذا أردنا الحصول على أول Post قام الـ user بإنشاؤه، يمكن إستخدام oldestOfMany، حيث نقوم بإنشاء علاقة جديده مثلا بإسم oldestPost، وإيضا إستخدام العلاقة hasOne ومن ثم تمرير oldestOfMany
public function oldestPost() { return $this->hasOne(Post::class)->oldestOfMany(); }
$users = User::with('oldestPost')->first();
كما شاهدنا بالأعلى أنا الدوال 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%'); }); }
مقال جميل جدا.. مبارك التصميم الجديد للمدونة.. عندي ملاحظة بسيطة وهي تغيير الخط في الكود إلى خط monospace كما في محررات الكود، فهذا أسهل في القراءة
بارك الله فيك و زادك من علمه مقال جميل و مفيد و نتمنى المزيد
مقال ممتاز وموضوع مش كتير واخد باله منه شكرا جدا وجزاك الله خيرا
شكرا لك ، سؤالي هل لابد من استخدام ( العلاقة ) قبل البحث ؟ الا يكفي في laravel استخدام mysql select statment فقط
مقال تحفة ربنا يكرمك
mahmoud
very good