لارافيل, Model / 2024-07-18

خيارات وخصائص للتعامل مع جدول pivot tables في علاقة many to many

خيارات وخصائص للتعامل مع جدول pivot tables في علاقة many to many

2024-07-18 وقت القراءه : 9 دقائق

جدول المحتويات


تحدثنا في مقال سابق عن علاقة Many To Many ، وكيفية إستخدام   pivot table، في هذه المقالة سيتم الحديث عن مجموعة من الإعتبارات والخصائص التي يجب إتباعها عند إنشاء أو التعامل مع pivot table.

 

لفرض أن لدينا الجداول التالية (books, authors) بحيث أن المؤلف له أكثر من كتاب، والكتاب له أكثر من مؤلف.

جدول المؤلفين

Schema::create('authors', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

جدول books

Schema::create('books', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->timestamps();
});

للربط بين جدولين (books, authors) نحتاج إلى جدول وسيط وهو author_book

Schema::create('author_book', function (Blueprint $table) {
     $table->foreignId('author_id')->constrained();
     $table->foreignId('book_id')->constrained();
});

 

تسمية pivot table والحقول

لماذا الاسم author_book

في عملية التسيمة يوجد مجموعة من القواعد:-

  1. يجب أن يتكون الاسم من شقين ويفصل بينهما underscore.
  2. الشق الأول من الاسم يجب أن يكون الحرف الأول منه يسبق الحرف الأول من الشق الثاني حسب ترتيب الأحرف الأبجدية للغة الإنجليزية aplanatic order.
  3. يجب أن يكون الشيقين بصيغة المفرد وليس الجمع.

 

محتويات جدول pivot table.

يجب على الأقل أن يحتوي جدول pivot table على حقلين وهما إسم الجدول لكن بصيغة الفرد ونضيف إليها id، مثلا إذا كان إسم الجدول الذي أريد ربطه هو posts يجب أن يكون إسم الحقل في pivot table باسم post_id، لذلك في مثالنا قمنا بسميته ب author_id والجدول الثاني book_id.

 

بناء العلاقة بين Models في علاقة Many To Many.

نستطيع وضع العلاقة في أي model وكذلك في الـ two model :

الخيار الأول: 

App/Models/Author
class Author extends Model
{
    use HasFactory;
 
    public function Books(){
        return $this->belongsToMany('App\Book');
    }
}

 

الخيار الثاني 

App/Models/Book
class Book extends Model
{
    use HasFactory;
 
    public function Authors(){
        return $this->belongsToMany('App\Models\Author');
    }
} 

 كما تم ذكره نستطيع أيضا أن نضع العلاقه في الـ two model وهذا يعتمد على طريقة وكيفية إستخدامنا للعلاقة.

 

تغيير إسم pivot table

على سبيل المثال أن إسم pivot table هو authors_books فيجب أن يتم إخبار الـ دوال العلاقات بذلك، من خلال إضافة parameter أخر وهو الإسم الجديد، وإلا لن تتعرف الدوال  على إسم الجدول

public function Authors(){
    return $this->belongsToMany('App\Models\Author' ,'authors_books');
}
 
public function Books(){
    return $this->belongsToMany('App\Models\Book','authors_books');
}

 

ماذا لو أردنا تغيير أسماء الحقول.

على سبيل المثال لو أردنا تغيير أسماء الحقول من author_id إلى authors_id ومن books_id إلى books_id فيجب أن يتم كذلك إخبار العلاقات بذلك، من خلال إضافة parameters أخرى تحتوي على الأسماء الجديده

public function Books(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id');
} 
public function Authors(){
    return $this->belongsToMany('App\Models\Author' ,'authors_books','authors_id','books_id');
}

 

إضافة Timestamps لجدول pivot table

إذا أردنا إضافة timestamps يجب أن يتم إخبار العلاقة بذلك 

Schema::create('author_book', function (Blueprint $table) {
    $table->foreignId('author_id')->constrained();
    $table->foreignId('book_id')->constrained();
    $table->timestamp();
});

في العلاقة يجب إضافة withTimeStamps

public function Books(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
         ->withTimestamps();
}

  

طباعة حقل الحقول الإضافية لجدول pivot table في ملف blade

للوصول إلى timestamp في ملفات blade، يجب إستخدام pivot keyword

{{ $author->pivot->created_at }}

 

إضافة حقول أخرى لجدول pivot table.

مثلا لو أردنا إضافة حقل is_free إلى جدول pivot فإننا بحاجة لتعريف هذا الحقل في العلاقة

Schema::create('author_book', function (Blueprint $table) {
     $table->foreignId('author_id')->constrained();
     $table->foreignId('book_id')->constrained();
     $table->timestamp();
     $table->boolean('is_paid')->default(false);
});

يتم تعريف الحقول الإضافية من خلال إستخدام withPivot حيث تأخذ مصفوفة من الحقول

 public function Books(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
         ->withTimestamps()
         ->withPivot(['is_free']);
 }

كما نلاحظ ان withPivot أخذ مصفوفة من الحقول


إدخال البيانات للحقول الإضافية في جدول pivot table.

ولإدخال البيانات لحقل is_free

$author->Books ()->attach($book,['is_free'=>false]);

 

تغيير الـ pivot keyword في ملفات العرض blade

ربما لأي سبب لا ترغب بالوصول إلى is_free من خلال إستخدام pivot keyword

{{ $author->pivot->is_free }}

نستطيع تغيير كلمة pivot من خلال العلاقة حيث يمكن إعطاء alias name لها من خلال إستخدام as

public function Books(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
        ->withTimestamps()
        ->withPivot(['is_free'])
        ->as('authorBoook');
}

هنا تم إعطاء alias name وهو authorBook ولطباعة is_free في ملف blade نستخدم authorBook عوضا عن pivot

{{ $author->authorBook->is_free }}

  

تحديد العلاقة لحقل معين في جدول pivot table.

ماذا لو أردنا تحديد العلاقة فقط إذا كان is_free = 1، بمعنى أن يتم جلب الحقول الي is_free = 1 

يتم ذلك من خلال إستخدام wherePivot

public function free_book(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
        ->withTimestamps()
        ->withPivot(['is_free'])
        ->wherePivot('is_free',1);
} 

كذلك نستطيع إستخدام wherePivotIn و wherePivotNotIn

public function free_book(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
        ->withTimestamps()
        ->withPivot(['is_free'])
        ->wherePivotIn('priority',[1,2]);
} 

 

إنشاء model للـ pivot table

كما نلاحظ أنه لم يتم إنشاء model  للـ pivot table، فغالباً لن نحتاج إليه،  لكن ماذا لو أردنا إنشاء model له للقيام ببعض العمليات الحسابية.

في الموديل عوضا عن أن يرث Model فإنه يجب أن يرث Pivot

class AuthorBook extends Pivot
{
    use HasFactory;
}

 

وفي العلاقة يجب تعريف هذا الموديل من خلال إستخدام using
public function free_book(){
    return $this->belongsToMany('App\Models\Book','authors_books' ,'books_id','authors_id')
        ->withTimestamps()
        ->withPivot(['is_free'])
        ->using(AuthorBook::class);
}

التعليقات
Mohammad
منذ سنة

لدي مشكلة call to a member function attach on null

إضافة تعليق
Loading...