Mahmoud Alrashidi نشر 11 فبراير 2021 أرسل تقرير نشر 11 فبراير 2021 ماهي العلاقات مُتعددة الأشكال ( Polymorphic Relationships) في لارافيل و كيف يمكن الإستفادة منها. 2 اقتباس
1 Sam Ahw نشر 11 فبراير 2021 أرسل تقرير نشر 11 فبراير 2021 إن العلاقات متعددة الأشكال هي أن يكون لديك نماذج يمكن أن تنتمي إلى أكثر من كيان واحد. يحتفظ هذا النوع من النماذج بالبنية نفسها التي لا تتغير بغض النظر عن النموذج الآخر المرتبط به. من الأمثلة الشائعة على هذا النوع من السيناريوهات هي (التعليقات). في مدونة على سبيل المثال ، يمكن أن توضع التعليقات على منشور محدد أو على صفحة مستقلة مع الحفاظ على الهيكل نفسه بغض النظر عما إذا كان منشور أو صفحة. أي بمعنى آخر ستبقى جميع الخصائص للتعليق ثابتة مثل (الاسم، تاريخ التعليق، محتوى التعليق،...). مع أخذ المثال المذكور أعلاه في الاعتبار ، لدينا كيانان: Post و Page. للحصول على تعليقات على كل منها ، يمكننا أن نقرر إنشاء قاعدة بياناتنا على النحو التالي: posts: id الرقم المعرف للمقال title عنوان المقال content محتوى المقال posts_comments: id رقم معرف فريد post_id الرقم المعرف للمقال comment التعليق date تاريخ التعليق pages: id الرقم المعرف للصفحة body محتوى الصفحة pages_comments: id رقم معرف فريد page_id الرقم المعرف للصفحة comment التعليق date تاريخ التعليق ولكن نلاحظ أنه باعتماد النهج السابق، وجب علينا إنشاء جدولين للتعليقات، جدول للتعليقات الخاص بالصفحة، وجدول آخر للتعليقات الخاصة بالمنشور أو المقال. وكليهما يقومان بنفس الدور تماماً ويحتويان نفص الخصائص، إنما الاختلاف الوحيد هو بالمكان الذي يتواجدان فيه (مرة بالمنشور ومرة أخرى بالصفحة). مع استخدام العلاقات المتعددة، يمكننا تبسيط البينة السابقة ومنع التكرار الذي حصل، فتصبح لدينا بنية الجداول كالتالي: posts: id الرقم المعرف للمنشور title عنوان المنشور content محتوى المنشور pages: id الرقم المعرف للصفحة body محتوى الصفحة comments: id الرقم المعرف للتعليق commentable_id الرقم المعرف للمكان الذي يوجد فيه التعليق (أي رقم معرف للصفحة أو رقم معرف للمنشور) commentable_type نوع المكان الهدف (صفحة أو منشور) date تاريخ التعليق body محتوى التعليق وبذلك نلاحظ لدينا عمودين جديدين مهمين يجب الانتباه إليهما: commentable_id و commentable_type. وبدورهما قاما باختصار تكرار جدول التعليق مرتين وتكرار البيانات. وهذا ببساطة هو مفهوم العلاقات المتعددة الأشكال. الآن لنأخذ المثال السابق ونقوم بتضمينه ضمن لارافيل: عند إنشاء الجداول للتهجير نقوم بالتالي: Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('content'); }); Schema::create('pages', function (Blueprint $table) { $table->increments('id'); $table->text('body'); }); Schema::create('comments', function (Blueprint $table) { $table->increments('id'); $table->morphs(‘comment’); //-> ستنشئ تلقائيًا عمودين باستخدام النص الذي تم تمريره إليه $table->text('body'); $table->date('date'); }); بوضع morphs سيقوم تلقائياً بإنشاء العمودين commentable_id و commentable_type. ثم عند إنشاء جدول التعليقات يمكننا تعريف دالة تساعدنا بالحصول على أي مودل آخر يملك تعليق (أي يمكننا مباشرة الحصول على تعليقات المنشور و تعليقات الصفحة) بدالة واحدة بدلاً من اللجوء لآليات أخرى أكثر تعقيداً، كالتالي: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model { //باستخدام هذا التابع نستطيع الآن أن نحصل على أي مودل يملك تعليق أي مودل الصفحة ومودل المنشور public function commentable() { return $this->morphTo(); } } وعند إنشاء الجدول الهدف (الكيان الذي سيحوي التعليقات) على سبيل المثال جدول المنشور: namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { //هذه الدالة ستقوم باستعادة جميع التعليقات الموجودة على منشور محدد public function comments() { return $this->morphMany('App\Comment', 'commentable'); } } نلاحظ قمنا باستخدام morphMany للدلالة بأن المنشور قد يحوي عدة تعليقات، وبذلك نستطيع الحصول على كافة التعليقات الموجودة على هذا المنشور. وكذلك الأمر طبعاً بالنسبة (للصفحة) نكرر الخطوة السابقة morphMany. يمكنك أيضاً الاطلاع على باقي أشكال العلاقات وأنواع العلاقات متعددة الأشكال الأخرى من التوثيق الرسمي في لارافيل. 3 اقتباس
0 سمير عبود نشر 11 فبراير 2021 أرسل تقرير نشر 11 فبراير 2021 تُعتبر العلاقات المُتعددة الأشكال من المواضيع المُتقدمة في الإطار، و العديد من المطورين يجهلون إستخدامها، بسبب أنها معقدة قليلاً، يُمكنك عدم إستخدامها لكن توجد بعض الحالات إذا ما استخدمت فيها هذا النوع من العلاقات ستُسهل عليك الكثير من الأمور، لنفترض أنك تعمل على مشروع، و هذا المشروع به مودل إسمه User و مودل ثاني إسمه Post و مودل ثالث إسمه Photo حيث أن لكل User صورة و لكل مقال صورة، و يمكن أيضاً إضافة نماذج أخرى لها علاقة مع النموذج Photo. قد يكون Product او أي كان. لنتوقف على User و Post بالإضافة إلى Photo فقط. في هذه الحالة كيف ستعمل؟ هل ستقوم بإنشاء نموذج PostPhoto لصور المقالات و جدول خاص به و نموذج ثاني UserPhoto لصور المستخدمين و جدول خاص به أيضاً، و إذا كان هناك نماذج أخرى تتعلق بالصور تُنشئ لها جداول أخرى في قاعدة البيانات أيضاً، ألا ترى أن هذه الطريقة ليست عملية! إذاً ما الحل؟ هل ستستخدم جدول واحد للصور photos و تضع فيه حقلين post_id و user_id و تجعلهما nullable ثم إن كانت الصورة تتعلق ب Post تضع مُعرف المقال في الحقل post_id و تترك الآخر null أما إن كانت الصورة تتعلق ب User تعكس الأمر. ماذا إن كان نموذج آخر يتعلق بالصور و ليكن Product هل ستضيف حقل آخر product_id لجدول الصور!! ألا تُلاحظ أن هذه الطريقة ليست عملية لأننا نضيف كل مرة حقل جديد، و كل مازادت الحقول التي ليس لها داع، تنفيذ الإستعلامات سيكون بطيء، و بالتالي فإن الأفضل هو إستخدام جدول واحد و حقلين فقط بغض النظر عن الحقول الإضافية للنموذج فنحن نتحدث عن حقول العلاقات. و هذين الحقلين هما: imageable_id سيتم فيه تخزين مُعرف النموذج سواء كان User او Post او اي كان imageable_type و فيه سيتم تخزين نوع النموذج مثلا Post او User على شكل سلسلة نصية و بهذه الطريقة تمكنا من إستخدام جدول واحد و تخلصنا من الحقول الإضافية، أيضاً إذا أردنا مستقبلاً إضافة نموذج ثالث له علاقة مع نموذج الصور لسنا بحاجة للتعديل على هيكلية جدول الصور. ملفات التهجير ستكون بهذا الشكل: جدول photos: <?php class CreatePhotosTable extends Migration { public function up() { Schema::create('photos', function (Blueprint $table) { $table->id(); $table->unsignedInteger('imageable_id'); $table->string('imageable_type'); // other fields $table->timestamps(); }); } // ... } العلاقات: النموذج Photo: <?php class Photo extends Model { // ... public function imageable() { return $this->morphTo(); } } النموذج User: <?php class User extends Model { // ... public function photo() { return $this->morphOne(Photo::class, 'imageable'); } } النموذج Post: <?php class Post extends Model { // ... public function photo() { return $this->morphOne(Photo::class, 'imageable'); } } هذه العلاقة تُسمى ( one to one polymorphic) أي واحد لواحد مُتعدد الأشكال يعني لكل مُستخدم صورة و لكل مقال صورة و لكل منتج صورة. ماذا لو كان لدينا الحالة التالية لكل مستخدم عدة صور و لكل مقال عدة صور هذه العلاقة تُسمى One To Many (Polymorphic) هي تُشبه العلاقة الأولى فعند تطبيقها نحتاج فقط لتعديل إسم العلاقة من photo إلى photos حتى تُصبح مُعبرة و نُغير التابع morphOne إلى morphMany بهذا الشكل في كل من النموذج User و النموذج Post: <?php public function photos() { return $this->morphMany(Photo::class, 'imageable'); } ماذا لو أردنا أن تكون صورة ما مُتعلقة بكل من النموذج User و النموذج Post، يعني صورة تابعة لمجموعة من المستخدمين و تابعة في نفس الوقت لمجموعة من المقالات، هذه العلاقة تُسمى Many To Many (Polymorphic) في هذه الحالة نحتاج إلى جدول آخر يُسمى Pivot Table يحتوي على التالي: imageables photo_id - integer imageable_id - integer imageable_type - string بحيث photo_id يُشير إلى معرف الصورة في جدول الصور الذي يكون بالشكل التالي: photos id - integer -- other fields حيث أن العلاقات ستكون بالشكل التالي: النموذج Post و النموذج User: <?php public function photos() { return $this->morphToMany(Photo::class, 'imageable'); } و في النموذج Photo بهذا الشكل: <?php public function posts() { return $this->morphedByMany(Post::class, 'imageable'); } public function users() { return $this->morphedByMany(User::class, 'imageable'); } افضل شيء للتعلم هو التطبيق يُمكنك تخيل سيناريو في ذهنك و تطبيقه. أيضا بإمكانك الإطلاع على توثيق موسوعة حسوب: العلاقات مُتعددة الأشكال 2 اقتباس
السؤال
Mahmoud Alrashidi
ماهي العلاقات مُتعددة الأشكال ( Polymorphic Relationships) في لارافيل و كيف يمكن الإستفادة منها.
2 أجوبة على هذا السؤال
Recommended Posts
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.